From nobody Sun May 24 18:42:57 2026 Received: from mail-wm1-f44.google.com (mail-wm1-f44.google.com [209.85.128.44]) (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 780C9175A8A for ; Sat, 23 May 2026 15:19:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779549548; cv=none; b=YESHpyNTgJeyBVw0MNBpY86azAqurNcXIt9AOOJfcHDNObvbeW3WQEmrNQskqTCfsY5Vz99zgIo4RVrxNeQHwxzmiM1Fq8vxYGgCBgEa0LwYTWOXQcNI+KqAp1uk/N6kt7LqptXAfRhVTNfg9i/ckOGL5rRZ7bwW9G0OuXokD20= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779549548; c=relaxed/simple; bh=vz71qJEbBcDlpKWN0PxoSnCxG34BC1gAh28THLKQFl4=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=dhuSjvC+RHwfZmVrmONygsKG6P6EVL/FXstXLV04gDAKiee2D2eSdXss08rjZDgmRe+C3CeDT0mo3Ki2w3RHyy4BhZz4X7peR+WLkxfLbsxoSOIvt4P9H0+yqaZfG3ZewFNFB/1aQxS5f+QOf3R7Eu3xK5GXRmPxvQmvWOAK4/U= 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=EBKfviHs; arc=none smtp.client-ip=209.85.128.44 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="EBKfviHs" Received: by mail-wm1-f44.google.com with SMTP id 5b1f17b1804b1-49041fb8c23so14999005e9.0 for ; Sat, 23 May 2026 08:19:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779549545; x=1780154345; 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=qMgDahtrFCXXY7J8kNXrJQw4x08PqM0mxJ2Gu2fN2io=; b=EBKfviHs16UbXtyaSwTBTnZ1469xPuxVeCJnp6V8Gs+54G2XGXdyW4r4OWTa+hEIK3 1ic5STbB1DQxCYyejS6fel+D4+uJDpAS/b0k0+YS29iQeug9jBzxIxMZRT/6o54gULpL znQv1P15AjJqMr7vV97AijlC8Zka6DE7ayUD6Ez4csjYxN0ngwFIa0nL9HGhZhphO8zF 7BZpBbMEfYss5lxkSRLh0OTrf+jk0+zSy6aNdC80cqxIkwiy4VDIdOmpo4av+40LlU1v Ewt9UXIO8S/kRwPpTl6Y67o8esvD4yPcNvGcDU3xSqtlfzWJ1n6zPE2RZ0dvFaT+xRYB 3kFw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779549545; x=1780154345; 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=qMgDahtrFCXXY7J8kNXrJQw4x08PqM0mxJ2Gu2fN2io=; b=cBIHbP8D1jaQITC5oIsY4L/AhAghJe7maEZQo2Rzsq7cXBH34Yeyp0NJn2cKrVMCIA 02ntK5YGculF3erOr4iPoHcL0D1NKzXIwtLLPaiudwkNq8QUv7kPH/h8Olj43Mp38Nvm 00YAkh+habUxE/WVhz4ejsp5em0WeSr0keGv1p5yenaFYtEnRFLPTWJphisL1x+j2igQ h++u9iaPpi5if15UvdMR9hdvYMQ3KS4UUh2I/Yg9R5qYqYx9ieKhNRx3s5Zsh0dXmFkN jRKZ18PpKnWUTukJtNeNN2rXbWawyPJJNEMJbslqeCUm4k7jZQze8K3u5AOmDF3LEoeo DiBw== X-Forwarded-Encrypted: i=1; AFNElJ/7seLN4dGGhBUUcBKNo0m3ECfQFHCYvF010zr7w6vZ9ZqUPQxWF8XhhvBVxCMoLJLtybKKSIrbKJcEhSo=@vger.kernel.org X-Gm-Message-State: AOJu0YxsehZPEz0hIwGuxOiwVHUNK0hxlx7u6JiMxStEIihxkl+v4fe/ Hh5nAxWLl2swzTqdPTa9rb9TzQVPx2Pdax7YAP77Bq882PVJzDVkZSAB X-Gm-Gg: Acq92OF+WEfNAxLFaTKiX6e84WzuO1M48IMiXx8UZmRTOlWmm3N2LXHoG4jyiLSnDmf waQ9//vCLPcTVnDv6s3Cj2kHGrcR7F9UqRqnN9ardTo8UWuRTcohoKEEJn44Q2WKaDhtLRls1t6 cKT26opYSs7E/MrZSCFkH21RXDuxatUZzvvYvXb1loOu5hBLJk9o5J6cSPWPsOJw9uB0teDATMx T7nORhRRgIhL8ET/fwY/15Ahh7TIDjlgzhWBSRQNbXniqRgHFxXORi5Dnk2iYTf2URdAFo3TGDF x2fkb6f8YoL82AWCtWPX9rP5OrP0PpsxBmGka3a64fdbCEAIZ4hSxiYPx3osTz497wjbq8+15uB oMXIkh+H07zxqSKfFtTWxJIKngiYTqaeNTFrBxqYMPp1c/iHQt6r8qqHjwbOwFRvDvAABpSnMxH SVTbFoz9biv3q+aAWYLUje0a75LcX0/9/g6smPmweo1oP5hA+ja+lLErqbl03u3KCvsaE0xFhRK OclGD/gdUwFF99Dmw== X-Received: by 2002:a05:600c:6383:b0:490:4717:970f with SMTP id 5b1f17b1804b1-4904717984dmr110577425e9.14.1779549544789; Sat, 23 May 2026 08:19:04 -0700 (PDT) Received: from localhost.localdomain (ip-89-176-136-191.bb.vodafone.cz. [89.176.136.191]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4904527dbf3sm111897405e9.6.2026.05.23.08.19.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 23 May 2026 08:19:02 -0700 (PDT) From: Petr Wozniak To: netdev@vger.kernel.org Cc: maxime.chevallier@bootlin.com, bjorn@mork.no, andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, linux-phy@lists.infradead.org, linux-kernel@vger.kernel.org, jan@3e8.eu, Petr Wozniak Subject: [PATCH net-next v7] net: phy: sfp: probe for RollBall I2C-to-MDIO bridge in mdio-i2c Date: Sat, 23 May 2026 17:18:59 +0200 Message-ID: <20260523151859.1665-1-petr.wozniak@gmail.com> X-Mailer: git-send-email 2.50.1 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" The "OEM"/"SFP-10G-T" quirk entry in sfp_fixup_rollball_cc() unconditionally forces MDIO_I2C_ROLLBALL for all modules matching that vendor/part-number combination. This works for modules that genuinely implement a RollBall I2C-to-MDIO bridge, but silently breaks modules that share the same EEPROM strings without having such a bridge. The Realtek RTL8261BE-CG is one such module: a pure copper 10G SFP+ media converter with no I2C-to-MDIO bridge. Its EEPROM reports vendor=3D"OEM", part=3D"SFP-10G-T-I", and -- critically -- Vendor OUI 00:00:00, making OUI-based differentiation impossible. With MDIO_I2C_ROLLBALL forced, the module silently ACKs the unlock password write, the MDIO bus is created, but no PHY responds; the SFP state machine cycles through the RollBall PHY-probe retry window before reporting no PHY. Move the probe into i2c_mii_init_rollball() in mdio-i2c.c, where the RollBall protocol constants are already defined. After sending the unlock password, issue a CMD_READ and poll for CMD_DONE up to 200 ms (10 x 20 ms, matching the existing rollball poll tolerance). A genuine RollBall bridge asserts CMD_DONE within that window; modules without a bridge never do, so i2c_mii_init_rollball() returns -ENODEV. mdio_i2c_alloc() propagates -ENODEV to the caller to signal that no bridge is present and PHY probing should be skipped. sfp_sm_add_mdio_bus() catches -ENODEV and transitions sfp->mdio_protocol to MDIO_I2C_NONE so the rest of the state machine skips PHY probing for this module. Any I2C-level error (NACK, timeout) during the probe is also treated as -ENODEV: if the module does not respond at I2C address 0x51 at all, there is certainly no RollBall bridge there, and SFP initialization should not abort. The probe writes are safe with respect to SFP EEPROM integrity: only modules explicitly listed in the quirk table enter this path, and the RollBall password unlock write to 0x51 was already issued by i2c_mii_init_rollball() before the probe for all such modules. Any module without a device at 0x51 NACKs the transfer and is treated as -ENODEV. Add "OEM"/"SFP-10G-T-I" to the quirk table so RTL8261BE modules enter the probe path; genuine RollBall modules continue to work as before. Signed-off-by: Petr Wozniak Reviewed-by: Maxime Chevallier --- Changes since v6 (feedback from Maxime Chevallier): - Remove redundant if (ret) checks after i2c_transfer_rollball() calls; the function never returns a positive value (always 0 or negative), so these branches were dead code Changes since v5 (Sashiko AI review): - Treat I2C NACK/errors in i2c_mii_init_rollball() as -ENODEV so modules without a 0x51 EEPROM do not abort SFP initialization - Replace fixed 70 ms wait with 10 x 20 ms poll (total 200 ms), matching the existing i2c_rollball_mii_poll() tolerance and preventing false -ENODEV on slow RollBall bridges Changes since v4 (feedback from Maxime Chevallier): - Fix commit message: replace "stalls" with accurate description of the RollBall PHY-probe retry window - Fix variable declaration order in i2c_mii_probe_rollball() to follow reverse-xmas tree (descending line length) - Remove spurious alignment space on "SFP-10G-T" quirk entry - Document that -ENODEV from mdio_i2c_alloc() means no bridge present, PHY probing should be skipped Changes since v3 (feedback from Jakub Kicinski): - Drop spurious Tested-by: tag -- author and tester are the same person - Use PATCH net-next subject prefix - Move -ENODEV handling from sfp_i2c_mdiobus_create() into sfp_sm_add_mdio_bus() so bus-creation code does not mutate sfp->mdio_protocol; the state machine is the correct place for protocol-state transitions - Split combined variable declaration for clarity Changes since v2: - Compile-tested and hardware-tested on BPI-R4 (MT7988A, 6.12.87) - RTL8261BE (OEM/SFP-10G-T-I): probes MDIO_I2C_NONE, link Up 10Gbps - Genuine RollBall (OEM/SFP-10G-T): bridge detected, link Up 10Gbps drivers/net/mdio/mdio-i2c.c | 61 ++++++++++++++++++++++++++++++------ drivers/net/phy/sfp.c | 16 ++++++++-- 2 files changed, 64 insertions(+), 13 deletions(-) --- a/drivers/net/mdio/mdio-i2c.c +++ b/drivers/net/mdio/mdio-i2c.c @@ -352,6 +352,50 @@ return 0; } =20 +static int i2c_mii_probe_rollball(struct i2c_adapter *i2c) +{ + u8 data_buf[] =3D { ROLLBALL_DATA_ADDR, 0x01, 0x00, 0x00 }; + u8 cmd_buf[] =3D { ROLLBALL_CMD_ADDR, ROLLBALL_CMD_READ }; + u8 cmd_addr =3D ROLLBALL_CMD_ADDR; + struct i2c_msg msgs[2]; + u8 result; + int ret; + int i; + + msgs[0].addr =3D ROLLBALL_PHY_I2C_ADDR; + msgs[0].flags =3D 0; + msgs[0].len =3D sizeof(data_buf); + msgs[0].buf =3D data_buf; + msgs[1].addr =3D ROLLBALL_PHY_I2C_ADDR; + msgs[1].flags =3D 0; + msgs[1].len =3D sizeof(cmd_buf); + msgs[1].buf =3D cmd_buf; + + ret =3D i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + return -ENODEV; + + msgs[0].addr =3D ROLLBALL_PHY_I2C_ADDR; + msgs[0].flags =3D 0; + msgs[0].len =3D 1; + msgs[0].buf =3D &cmd_addr; + msgs[1].addr =3D ROLLBALL_PHY_I2C_ADDR; + msgs[1].flags =3D I2C_M_RD; + msgs[1].len =3D 1; + msgs[1].buf =3D &result; + + for (i =3D 0; i < 10; i++) { + msleep(20); + ret =3D i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + return -ENODEV; + if (result =3D=3D ROLLBALL_CMD_DONE) + return 0; + } + + return -ENODEV; +} + static int i2c_mii_init_rollball(struct i2c_adapter *i2c) { struct i2c_msg msg; @@ -371,11 +415,11 @@ =20 ret =3D i2c_transfer(i2c, &msg, 1); if (ret < 0) - return ret; - else if (ret !=3D 1) + return -ENODEV; + if (ret !=3D 1) return -EIO; - else - return 0; + + return i2c_mii_probe_rollball(i2c); } =20 struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *= i2c, @@ -399,9 +443,12 @@ case MDIO_I2C_ROLLBALL: ret =3D i2c_mii_init_rollball(i2c); if (ret < 0) { - dev_err(parent, - "Cannot initialize RollBall MDIO I2C protocol: %d\n", - ret); + if (ret !=3D -ENODEV) + dev_err(parent, + "Cannot initialize RollBall MDIO I2C protocol: %d\n", + ret); + /* -ENODEV propagates to caller: no bridge present, + * PHY probing should be skipped for this module. */ mdiobus_free(mii); return ERR_PTR(ret); } --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -607,6 +607,7 @@ SFP_QUIRK_S("TP-LINK", "TL-SM410U", sfp_quirk_oem_2_5g), =20 SFP_QUIRK_F("ETU", "ESP-T5-R", sfp_fixup_rollball_cc), + SFP_QUIRK_F("OEM", "SFP-10G-T-I", sfp_fixup_rollball), SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc), SFP_QUIRK_S("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g), SFP_QUIRK_S("OEM", "SFP-2.5G-BX10-D", sfp_quirk_2500basex), @@ -2029,10 +2030,18 @@ dev_info(sfp->dev, "probing phy device through the [%s] protocol\n", mdio_i2c_proto_type(sfp->mdio_protocol)); =20 - if (sfp->mdio_protocol !=3D MDIO_I2C_NONE) - return sfp_i2c_mdiobus_create(sfp); + int ret; =20 - return 0; + if (sfp->mdio_protocol =3D=3D MDIO_I2C_NONE) + return 0; + + ret =3D sfp_i2c_mdiobus_create(sfp); + if (ret =3D=3D -ENODEV) { + /* Probe confirmed no bridge present; skip PHY discovery. */ + sfp->mdio_protocol =3D MDIO_I2C_NONE; + return 0; + } + return ret; } =20 /* Probe a SFP for a PHY device if the module supports copper - the PHY -- 2.51.0