From nobody Sat Sep 26 03:17:25 2026 Received: from mail-wm1-f43.google.com (mail-wm1-f43.google.com [209.85.128.43]) (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 7933D3D6CB0 for ; Fri, 4 Sep 2026 19:03:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548594; cv=none; b=MqmfUCQLbHdGp21bzDO/O2zZy5XyWUm5e3yM4P4q9VyWsHDt4oSVt9Pr5quiSzu3Fho2mlOel67jSvpH3HD++KA3v19n1RuD2gWm5VUrrSbSkcMRQbS+n0D9zLFXVU27wP6548PQXhpTzpBHS/LHy1CfPFiJoUY+IjXVqnzAoL8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548594; c=relaxed/simple; bh=8R4/NVGFvwwBFp0K57CYXj8nWvSaeS/7ZTI2XPzrhfM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kYCjilp7m5a1foCaoQ7gMkYDislGDmuYkdsdACZO6aND7orhfYj5S0jNBH2dP2FDOMmffImAiyDbxy9+OEe5wMaayGpqxNaQR52Ki687w3BDZ161NYgWehiGgmtCSImY0SmfPX2FXeEofN3d4yeQM+ATWAM9ZxKkFX8/Rgdv1/A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la; spf=pass smtp.mailfrom=lex.la; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b=Hg9gWEjp; arc=none smtp.client-ip=209.85.128.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lex.la Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b="Hg9gWEjp" Received: by mail-wm1-f43.google.com with SMTP id 5b1f17b1804b1-4957eefd361so10927415e9.1 for ; Fri, 04 Sep 2026 12:03:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1788548588; x=1789153388; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Yf0aKsZ1iXAzFzECqXKGTn9Dxl8O6Scv1+EVxQaYW8o=; b=Hg9gWEjpFlpCWBIKgdC+r0KnvaBaPjFjwf12HsN02VdFc/i/PZWCJ8+twEBFuGRwSF XkCjTx3NPvw7pBjywkv2+nnGRHyEqla8he+6VScySpxjng8z1t5qKxjcI6QqtPMsiGTv 4XrrT8itWSTjLtF3J6y6goGmkkKu43yqaOrPCiiJdvuIkka2gWqnPXrBvZxQyImSRBjw 9AJKlvOE1pTP6524D6iDcJ1YMnMgeNMEtf3/wJqMa1ydWPv2XFDoLxYgdm7YKo+7FWiz 7bZsjusPYtE9bFfNgoYJeTb/gM4sOS0lCw0cvYk2hGz49cJ3D3V/yXa4aEuylLoZ2FoF nD/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788548588; x=1789153388; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=Yf0aKsZ1iXAzFzECqXKGTn9Dxl8O6Scv1+EVxQaYW8o=; b=NkD8LGTt0pZyqEls9XL8g9gcf/uw9DZRj9HOs/ASFE10JdjK+1SoyBJKySKoQRXdLC uYSyx54F6fqycptpZScL5vs0f89QzBlCJ27r535e17PT9Nf8f38hJSGHtB654cCU87Jm T30kQRXvLEPBwmnxvOvbWl0GlMYj2Fnwv/UTBe/yxl0C57+GqFRdsfXA0oIpnj/Lbk1Z B5+SzhBgKLIWPa6efRGXcjGabM6jji/O310Q4qyqNLT723u+JBSasfM903MN1IlTavwu iAaywZotyr4RPEl4nAFcj954rBjzMAqvnTNWqfDbyyVz1S1YPtCgbMA3YZ0DBYsEQdmw eWZw== X-Forwarded-Encrypted: i=1; AKwUvBxbQ2ilSsPmQKLbsJER4vVvRqWWz2npTtnetAxVXU0alP9T8UQq1W3mHYBMIVY8X3nKNugSHeO8cwIQc9s=@vger.kernel.org X-Gm-Message-State: AFuF++keXYyHiTNNkXE9+ftxoFaEdxzbZoYqYPWHyrOCgIb734loTdQE 9JtNNrcfa0EARoCvGBjhT1BtQEPd4YlKwuBfuofTgJsWv4cIcSRgi5ME30O9LRnjdTg= X-Gm-Gg: AYBFou1da80agQAlAgHI9kr+WUMircO+/2E+P6waTA+NmStNgm1/pKxPxVNeUZq3j1f hdjSVcC0HhTi7nQzutYTkoBgQjVukkbRrmk8GyIE5P2U3xCDyK2WfxvrcI51y/rpV5OzSzdsjFh M+sRBZZ+jzA5J1raj1T6A8EeWOKsi7BB+W1eKrcDdjxchiYCjL3QO6+JaERg0Iv/EImvQcCbtsN DbyLyNTfUMenMzAPMmxk8QV0VSz7okDdWiO9I4XfFoa8YlSHsHZeH8/wYrGLBNa0epFCYuQ2Uza MI3WX3/gYmzfOqtYv2/4v7TdN6nAThGMHRI62rNxHz6SRMeu4l64Ohvx6CKLoUqeoR9ml0H5sLb exqRjDtv5/lgS3MAUYzwp657/YwSiJxk/Ix2IJRMNxsVwokC+vxyDWWvL/HTNUi1CqL/G42KPYX 7NC9FqBvVezBP8miM3zYP6/SxXBAb5SR3jwF/9P48= X-Received: by 2002:a05:600c:46d1:b0:493:bd2a:93be with SMTP id 5b1f17b1804b1-49cf820c992mr86205475e9.6.1788548587745; Fri, 04 Sep 2026 12:03:07 -0700 (PDT) Received: from remote-01 ([84.17.55.227]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49cee60d8a6sm172195485e9.10.2026.09.04.12.03.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2026 12:03:07 -0700 (PDT) From: Aleksei Sviridkin To: Andrew Lunn , Andrew Lunn , Heiner Kallweit , Russell King , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: Eric Woudstra , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH net-next v2 01/10] dt-bindings: net: add Airoha EN8811H PHY MCU Date: Fri, 4 Sep 2026 19:02:55 +0000 Message-ID: <74144d4bcef8546126b66d9541ed2233a2c04aec.1788548229.git.f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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 EN8811H answers its PHY ID from power-on, but a link is only possible once its MD32 MCU runs firmware that the host loads over MDIO into volatile RAM. On systems that keep the firmware files in a filesystem, the files arrive long after the MDIO bus was scanned, and the PHY node alone cannot express that gap. Describe the MCU as an MDIO device of its own, with the PHY node on a child bus underneath it. The device downloads the firmware when the files appear, or adopts firmware the bootloader left running, and registers the child bus only then, so the PHY never becomes visible before the chip can serve it. The reset line belongs to this node, not to the PHY node: firmware lives in volatile RAM, so reset may be asserted only while the MCU is not executing it. On a PHY node the line would be pulsed by every phy_detach() and wipe the running firmware. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- .../bindings/net/airoha,en8811h-mcu.yaml | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/airoha,en8811h-mc= u.yaml diff --git a/Documentation/devicetree/bindings/net/airoha,en8811h-mcu.yaml = b/Documentation/devicetree/bindings/net/airoha,en8811h-mcu.yaml new file mode 100644 index 000000000000..99a494f6ca1e --- /dev/null +++ b/Documentation/devicetree/bindings/net/airoha,en8811h-mcu.yaml @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/airoha,en8811h-mcu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Airoha EN8811H PHY MCU + +maintainers: + - Aleksei Sviridkin + +description: | + The Airoha EN8811H 2.5G PHY is built around an MD32 core that executes + firmware from volatile RAM. The chip answers an MDIO address from + power-on, but the PHY function does not exist until firmware has been + loaded over MDIO, and it disappears again if that RAM is cleared. + + This node describes the MD32 core. The PHY function answers on a child + MDIO bus below it, at the same address the core occupies on the parent + bus, and only while firmware is running. + + The reset line is wired to the core, and asserting it clears the + firmware RAM. It therefore belongs to this node: a reset described on + the PHY node would be pulsed by that node's own lifecycle, whatever + the core is doing. + + A board that has firmware in hand while its MDIO bus is enumerated can + describe the PHY on its own, as airoha,en8811h.yaml does, and that form + stays valid. This binding is for the boards where firmware arrives + later, so that there is no PHY to describe until the core has it. + +properties: + compatible: + const: airoha,en8811h-mcu + + reg: + maxItems: 1 + + reset-gpios: + maxItems: 1 + description: + The GPIO phandle and specifier for the reset signal wired to the + MD32 core. + + reset-assert-us: + description: + Delay after the reset was asserted in microseconds. If this + property is missing the delay will be skipped. + + reset-deassert-us: + description: + Delay after the reset was deasserted in microseconds. If this + property is missing the delay will be skipped. + + mdio: + $ref: mdio.yaml# + unevaluatedProperties: false + description: + The bus the PHY function answers on while firmware is running, at + the same address this node occupies on the parent bus. + +required: + - compatible + - reg + - mdio + +additionalProperties: false + +examples: + - | + #include + #include + + mdio { + #address-cells =3D <1>; + #size-cells =3D <0>; + + ethernet-phy-mcu@d { + compatible =3D "airoha,en8811h-mcu"; + reg =3D <0xd>; + reset-gpios =3D <&pio 14 GPIO_ACTIVE_LOW>; + reset-assert-us =3D <10000>; + reset-deassert-us =3D <20000>; + + mdio { + #address-cells =3D <1>; + #size-cells =3D <0>; + + ethernet-phy@d { + compatible =3D "ethernet-phy-id03a2.a411"; + reg =3D <0xd>; + interrupts-extended =3D <&pio 15 IRQ_TYPE_LEVEL_LOW>; + }; + }; + }; + }; --=20 2.53.0 From nobody Sat Sep 26 03:17:25 2026 Received: from mail-wm1-f43.google.com (mail-wm1-f43.google.com [209.85.128.43]) (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 2DD4A425872 for ; Fri, 4 Sep 2026 19:03:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548595; cv=none; b=tjg9m7hCbozSqt0ao4ucqfxxXC96HgdO+4dX3U8krnaslGM7aVTzS8arrEa3Tm6OTCycxqvRE0i1P0p7/NNexgJmudZkA/2AEBWuJUwTNb57ciUZEHvemw26y/Ihak9sORb8LQemW8m0VpgN1lmXe1lnzbIrL9z7ylrBBtIXpXU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548595; c=relaxed/simple; bh=UNJv9lvrdAaMKo4znGMIdBsuP3iVdeueDxYAlJd0x+M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aTZanVojjlZo56Pv3rWtbjj9e95k+ZZBb9q77oe/cTDMYmkA9gtjW95lXXZBBhrmqFzuW7/viuOvFDqI45t2a41OC8cl0ARXqXK1yS/wwpszN3jNYIX3dz6wdH4AgUwCzo82wE/VKGzM1UZO10GtMtm51nY/qS5zKpaNuK/DnNs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la; spf=pass smtp.mailfrom=lex.la; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b=I1/+rlfY; arc=none smtp.client-ip=209.85.128.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lex.la Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b="I1/+rlfY" Received: by mail-wm1-f43.google.com with SMTP id 5b1f17b1804b1-49ccfbe062eso11997555e9.3 for ; Fri, 04 Sep 2026 12:03:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1788548589; x=1789153389; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Tu1Vd9Fy3KvBC8Ugis84GLswT2AxZGxIE45TX7gUkfY=; b=I1/+rlfYqhrOBqqk+5AUuj4SRBYZ8fZTB9H/xYRafSXUTtlOcA2pF0CU1oUsscUZ3q kLMO2op20yg+jNd2Ak4R7fA06woK3Fnkjv7AWYIdBJZiN7vNbOzlgK8qEffbixiuPuKd pxxN/2D2ZsNiziPlgy2MzfojhcFX+P/dEcTje556APW9swPeMOaGKKSeKLSSi3fYzWID 91Y0IPBwI1t1FaO5RPrKFEb24qX7wQk9qMpuryrkSyLZ3HtNTVMzIl64hKDOb5T1KMGK veTexRm4EkTSPoFD4jkwOojjT88zcepaBE63QfShn6PszNKhWUaCBx6AuNSgh9UTYf6c Nk+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788548589; x=1789153389; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=Tu1Vd9Fy3KvBC8Ugis84GLswT2AxZGxIE45TX7gUkfY=; b=pUX8fMIQD0HjbD6b+hQcEX9/dE88wozL5D8WI2aWzUZJUnK8vjM6M6P9hU2VGuXJDX QTFtgnsgleNdRDgfGJMDMEJmNr6U92LLqDU3qY9IOjCO8y1L704DT+UAQxB9mcKoWTPP hLpYuF7vBcEbqmh6nJc5ZSLqKdLFrGOsK6KqyueKdihejnCAOGOVQj/XAyJYfk7n/OOS AO91EG2zSL68Rsp+FhSpQ++3kF5nK4ZRfDqcUje3W6OXO2yc0kWhzKWOvK/Xu8am02nw TMW2h4tOJy79Gg678jpk4+Dx83PaE9XteTtqhw+cohreUPDbHfPCh9JhWqVuQ58i2QjG kHEQ== X-Forwarded-Encrypted: i=1; AKwUvBxVge3MWRx1FlgOvgTYWHtIWDANlpdXUPGe3WKSidVPuubnEVmAxsW6t/yp6HO00TkHPJqXDNMuvb3LMCE=@vger.kernel.org X-Gm-Message-State: AFuF++m+Rrm2W2bDrlI3ZakVYlR2vTyMwwZWxC4/Nk9JrW8+jVcO8fTu ql+b/pS7+Ou8sA8OcQVY2uceAL+k2pUDQqkaInHHdXcnNTvi8p5ByxuTpoTQydqV8lg= X-Gm-Gg: AYBFou2G37RHAZnoeR7DhVZyR9VxlqjxIHwcOBG8E8EWXgb5q1Isd9Pr6czIgsxiA9b ofs63jl7dIceSYrdnJyXEtwMrHXYm2dJ8rbYsQReXobBfedkdfk0VBtUdDjJzdvOWaiXhVFWS7x XVMF9JKiP1oHyKUVEi3LyXZuWz35Lbi32QgY9zbc/TbU1UxDh+O73kFkvEyibbzGGbbrVuXImvZ 1/UyM/a7clln9k7Az18KdUIxHUTTUt6c/70Im+WYnv4ENLWbE1Nq0DJN9u5yqOec9eMNdA0leFB Gpsl4uWwL6pZw5vTC9zsWXev+bfvt9XB7/BRSO6zFzw80eAbd/gHu3ssHy3Z6rUXjFPCY6tLJ2q qA96hb6OowTeHDG2WhWvZfRgNR0KWZw2pYmvGiE0d//JgpVW9irMP455Ht5KZmGiHuaRXvNmf+f yKDGiCY+fdkjzoSWZzi/KBoXsTluqZWD9PtC4OmOo= X-Received: by 2002:a7b:cc91:0:b0:49c:ff9f:f6b6 with SMTP id 5b1f17b1804b1-49cffa00196mr22006655e9.6.1788548589176; Fri, 04 Sep 2026 12:03:09 -0700 (PDT) Received: from remote-01 ([84.17.55.227]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49cee60d8a6sm172195485e9.10.2026.09.04.12.03.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2026 12:03:08 -0700 (PDT) From: Aleksei Sviridkin To: Andrew Lunn , Andrew Lunn , Heiner Kallweit , Russell King , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: Eric Woudstra , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH net-next v2 02/10] dt-bindings: net: ethernet-controller: add phy-needs-host-firmware Date: Fri, 4 Sep 2026 19:02:56 +0000 Message-ID: <3d0ecd9c0bcc28fbbce6f7df2b6995f2e8c78431.1788548229.git.f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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" A port can reference a PHY that cannot be identified or driven when the controller connects to it, because the firmware the chip needs is not in hand yet. Such a port is dropped at setup and stays unusable for the whole uptime, even though the PHY works seconds later. The flag declares that the PHY behind phy-handle is expected to become usable only after this controller has probed. A consumer that sees it keeps the port and connects the PHY once its driver binds, instead of failing the connect. The prefix names the entity, like the other properties here that name what they describe rather than the controller; a PCS needing firmware would get pcs-needs-host-firmware by the same rule. It sits on the controller here because that is where the waiting happens. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- .../devicetree/bindings/net/ethernet-controller.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/net/ethernet-controller.yaml= b/Documentation/devicetree/bindings/net/ethernet-controller.yaml index 1bafd687dcb1..ce4a7a6f605f 100644 --- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml +++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml @@ -108,6 +108,13 @@ properties: $ref: "#/properties/phy-handle" deprecated: true =20 + phy-needs-host-firmware: + $ref: /schemas/types.yaml#/definitions/flag + description: + The PHY referenced by phy-handle runs firmware that the host must + load before the PHY can be driven, and so is not usable for as + long as that has not happened. + ptp-timer: $ref: /schemas/types.yaml#/definitions/phandle description: --=20 2.53.0 From nobody Sat Sep 26 03:17:25 2026 Received: from mail-wm1-f52.google.com (mail-wm1-f52.google.com [209.85.128.52]) (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 672643E9C18 for ; Fri, 4 Sep 2026 19:03:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548596; cv=none; b=hjOz84FEzgisyWC16a9WCBNoH4LSlAUR7XQhaXSdmnCpag0LgpZEZb7QbXjgMK4ADFNwXs47sdejrp7sFRYQI7gUuizNIAxKPyL1Sn3rjjE1QgpwiFnC1stDeOp33AzrFXepNMv3Lbz53Dv9QWOoPaypdKX7FvnfkQVKWjPDEOQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548596; c=relaxed/simple; bh=g+9YyrCCqwkQj25pBhc80E3Us3WQgU4LquXHfZWmm68=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Jxh1chxfxz5dOXRSwG0xP6lyB8uB4+kcEybOGWHpUePS2rEj6qsqc5DJHm7ZQOsFdKztx4k3yqM5e2sMB5NW/6nvODA/TM9pOcXj5yw1A5moZVQq796cyoqiZPUwKGumoHGgCvkgCsTMIVXHO/772ErOLyITUOWr23Zs00gC5EE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la; spf=pass smtp.mailfrom=lex.la; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b=SFNrcwsI; arc=none smtp.client-ip=209.85.128.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lex.la Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b="SFNrcwsI" Received: by mail-wm1-f52.google.com with SMTP id 5b1f17b1804b1-4957eefd361so10927665e9.1 for ; Fri, 04 Sep 2026 12:03:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1788548590; x=1789153390; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Lj3tsvbtNJDWZnFH5pUKMKwa2zoY5MXACQtNrJLPngI=; b=SFNrcwsIy1g7mN+pUwAi1aZAClIb7TZzx20jZyB6X8DR1SoBcTtGPc9dTBqiGx4N47 92/UGLYM4+sEWDBtLzKuJidIcMBBrc2D/e8QHkgxJpJ+z4agD2Rue8alZ8a1j3eKDErc paYRvTzOUIWMAj0Qkvfy7GdhbMeLUPjZFTeMGqKAtS8G2ty7L5tF/VynaEMJI41CzFt9 Nfvo+7ma0SEAdYZBtGjZ24ZEAeEMpq3mSht1OocPg52EnZFs4tjgQEmA6ofAMNhW454w btePYf77B0l2OZhJYgUgQVtE3vMJ2SDq5Hl7XqAIjqZCw+wVcWimsY8WZvUkMIL0XgVr qunw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788548590; x=1789153390; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=Lj3tsvbtNJDWZnFH5pUKMKwa2zoY5MXACQtNrJLPngI=; b=qB8pwqpD7gAsVRpHm38iP/sc+ws3gBBWiCa2HImxN9sVmUC9e3DTwJ/aH+t3mXEhMZ f1vq8OJv/HQ4A/WP+kO981csnHkUNeLYEQ2jFU1FkmITN5s6RAOTShFN7+0kn9h0SjLs I8NpbjxBmT2tbuQMb7J/uZWNpDzz6oAawWcg5OA+ZT8eez7u0D1u5d7XhOIs2eQ7VqdB s4iCPAptSUFNVeB9JAKekWEnHSCUAxAtMF888/PMoCg+ATFOzJveZ4693OHA8f0OkgyQ 5NqzsQEfWFueAvZ9G1qldjTLogh0gqW1MaQOxuEigwJSKvBGk3ni9wOY03wMbYyKgpAO GL4A== X-Forwarded-Encrypted: i=1; AKwUvByeDNeE7YC/d5iSUeoMSi4ayi0oio1gBcsAWYK3TRdyUgPJ74vmM6d/m3fGAIoda/f0GM8zW8kq4b/aqWs=@vger.kernel.org X-Gm-Message-State: AFuF++kmUbDX9M0AzBPPdoTE82RgG28oG86bdBFGPDxuVH1MSHGhko+i y/UvYeBAU8jdbver44CSgZuEOTl+KEbaJBZ6s6PoSlXiY8XJjb8K9LKISnLPS/b4ecc= X-Gm-Gg: AYBFou3fxhWbiT7vH7K3Vxd25bgUm+QnUWKbx9vTeLV5mwT2IskNbd4YxJsd2SdrDAc 2vOcyunx2GyHeb+OhlQMSHjFPFdCWTVCsDRS9HDCaPY3fvJ9Se/eXj6QtOkWcwrhb19OcHJ7Vyh ZGbBVIdXDna38YdEGRueAfIAXMJP6EQhIIWF9aGz6Oop2KwEfpOEANC5SUKPARJoCNapiMYF4Px ZPzkihQ133qJp5VVEwapOQ0Q/Idv2msfJuOnptKc0ibZdvjg0KzbBq5A+/+iBzUKBAjuF39DbVf FoeiJnhzYdurJ7uMT0Gwec89UgZ0fTmK3kTDOwUeDpGFNpxc5NLOGEkCOCQsAt1jO6bcBu8RUmh tPe7vlxRQ6hdh5S3NlYzB/S/84U6CbN9np8PHJ9mFN2waX96oIIWzCjbBngNvTfmiCp0GsHkFIv 7z3j1CDBefhPnFiqOhVOsppyv6CZ86ZFnOkFeVmWA= X-Received: by 2002:a05:600d:864a:10b0:49c:fc89:59cb with SMTP id 5b1f17b1804b1-49cfc8960ccmr41262475e9.5.1788548590621; Fri, 04 Sep 2026 12:03:10 -0700 (PDT) Received: from remote-01 ([84.17.55.227]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49cee60d8a6sm172195485e9.10.2026.09.04.12.03.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2026 12:03:10 -0700 (PDT) From: Aleksei Sviridkin To: Andrew Lunn , Andrew Lunn , Heiner Kallweit , Russell King , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: Eric Woudstra , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH net-next v2 03/10] net: phy: add mdiodev_lock() and mdiodev_unlock() Date: Fri, 4 Sep 2026 19:02:57 +0000 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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 __mdiodev_* accessors require the caller to hold the MDIO bus lock, but the wrappers that take it, phy_lock_mdio_bus() and phy_unlock_mdio_bus(), need a phy_device. A driver bound to a plain MDIO device has none, and must reach into mdiodev->bus->mdio_lock itself. They sit in phy.h beside those wrappers because struct mii_bus is defined here, not in mdio.h where the accessors live. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- include/linux/phy.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/linux/phy.h b/include/linux/phy.h index 3d8afe6b7f1c..8c10c8ae21b1 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -2284,6 +2284,16 @@ static inline void phy_unlock_mdio_bus(struct phy_de= vice *phydev) mutex_unlock(&phydev->mdio.bus->mdio_lock); } =20 +static inline void mdiodev_lock(struct mdio_device *mdiodev) +{ + mutex_lock(&mdiodev->bus->mdio_lock); +} + +static inline void mdiodev_unlock(struct mdio_device *mdiodev) +{ + mutex_unlock(&mdiodev->bus->mdio_lock); +} + void phy_attached_print(struct phy_device *phydev, const char *fmt, ...) __printf(2, 3); char *phy_attached_info_irq(struct phy_device *phydev) --=20 2.53.0 From nobody Sat Sep 26 03:17:25 2026 Received: from mail-wm1-f48.google.com (mail-wm1-f48.google.com [209.85.128.48]) (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 B41F4471411 for ; Fri, 4 Sep 2026 19:03:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548600; cv=none; b=Ftq1hCGktylygUbGAvgARtK445CgvuLT7OZN9QW0vepptqlSPoTuccYdOO0eSBrQdm2xuJ9GekXmIuk2lf9dUqDHXF33O9GYccYYGRWfcTWQqLTnM0dQAFCqglc2AMq+VK8K+ofk/HvEkieyZAih8XI0hJgZHT2KgstWpVCqMGI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548600; c=relaxed/simple; bh=mzH/5XaUhv6NQCYgufBy5oWC9jpITM+/znfPg5sAlv0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TtpiiB9ay8G698YkN6poeaJA1XEC75BmxKpmM5vFcp7ZMszkkPtPMODRJBG7uu/AlZ2hygTvhULY5KOuwDv67lWL255SYnz2fya6OE47dttiBSvFUjtgozutKQVJ1Wy1mMNDgXbUgYQNqF6rAOvuDWXn9txMb6BHQqbqFuKcrxk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la; spf=pass smtp.mailfrom=lex.la; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b=KVKcBtGa; arc=none smtp.client-ip=209.85.128.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lex.la Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b="KVKcBtGa" Received: by mail-wm1-f48.google.com with SMTP id 5b1f17b1804b1-4957eefd361so10927855e9.1 for ; Fri, 04 Sep 2026 12:03:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1788548592; x=1789153392; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=YfiP06w66PJnEqo2UKKQtS6GK/rrfhVqIhL6B6Ho9XA=; b=KVKcBtGa7qkMiK+MV4F72Oz3G8+Ner++Con1fulnsUgfrO7Nj4sDQM48QdrFYASgah QezFTD8zwvvFXZch1eLMIaS1iBg5ilZobHKrSIKmWkNEobPu4V46Y7hxpGGMniKU8jd4 8TSbdEuqg8klhPChzKjRGaaAt6VfAUlAT2kkcclHpiWuLwNQTSX3OfKOYKKragH5rC7B ja7SFzOjGgMb9NJ8uDjGQtUIEQe9joRTX5uQ/VjRfGBFcTEo8cZgqdsJe3xQimBWyn6I Eh6utyplrQ7aThh6/BqXBxIFTm7BJg8qEGwLK779vZeJXz5HMb0gYfpRs7s83egUMrj5 WjpQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788548592; x=1789153392; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=YfiP06w66PJnEqo2UKKQtS6GK/rrfhVqIhL6B6Ho9XA=; b=WA0TuAUE/MnwAeX/HBpvCoGkieq7AJaeVlKBUrmWjhjScJjuB5fKblVstAumqfmUx3 KApynR0KR73TRIy+dt85iYn9hDQ0gR7O4N0njJ0pjWdyB8k6TDSQx8r5hi8TP23Spv3E d12E635oal4yQlLDXufIuH3jzoJOUjFO84ra3dEUZYB6JZ2ViBUNy61T+T+UFyLHHGtR B9xp8tJ6jMCvfHStP5WDtchBsp03lCPxhA0dkqTkDKKE129a5SHoCGOtb0GM9OMyDqH2 onNzU3M/4W20mNddWT3lQ5icyLw5MP93gve16aFTDQdK4hNcX0apreHgpbEBFRvtUTa5 qFcA== X-Forwarded-Encrypted: i=1; AKwUvBzYbtmD+LOrl4T3/disNqmMA0XLOYAAhCzMAm9q0du/1lYjiPUo6T0zfEPLbGW6cirIum5AWt+x7sLkygA=@vger.kernel.org X-Gm-Message-State: AFuF++mLCE1U2xV9Id1nvCs1dx21ruN5+OknNeHF4GnryJd5PwNGE9Bv baQlTTkdI4Rp5Qw+h6AO0xNvWviMOJOfIgAxQIRy8T1eDkIf9rkVnMVJjyXiFuwPDXI= X-Gm-Gg: AYBFou2BD0wWe+9tr90KoM0zbSczv05V1VzWd8gIGTzer7ZBfr53EHxSGNFBbTXpQVt mWrniWNXHbKxEuIEzvIBMiWs+fLVpTTbPknB7JZVUuwtigojHCDEmEK+Uc1MgHVUHv5HWo/KsFm Gwc3Iv+WvN1iU2iybAmyFJwJz41wJGmgqW+7+dxvSeIn1/V0Dv/ZUr+nJjr6i5gxw8tY+kuNImn 8VaQJESB5wmB2/KpXrjvvzQOqLhRLe0n3gIOFcQi8tbtRnwKfnNVJV7fmNMBu4HNth9xjLVn+TY byylDw2sNO80h2PGYsm4WAjSyxd1EIh3uOOCj9muBu/9WKQp/msKt40i1YEnm9r8l4JMSlt1eHi KFLmSsgBo5ajCTDw99EjiTEmHXM57ythpy3hSmQaS3fuBmSzJ1oJmB1A8a21WtX0ix2avSPhYb0 eiY3P8MD8sRx+AD8plr/BwBaYhrvX9IUlFec2ux9ZvWkZYq/Ljyw== X-Received: by 2002:a05:600c:310d:b0:49c:dc14:d681 with SMTP id 5b1f17b1804b1-49cf81e5449mr84605115e9.3.1788548592018; Fri, 04 Sep 2026 12:03:12 -0700 (PDT) Received: from remote-01 ([84.17.55.227]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49cee60d8a6sm172195485e9.10.2026.09.04.12.03.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2026 12:03:11 -0700 (PDT) From: Aleksei Sviridkin To: Andrew Lunn , Andrew Lunn , Heiner Kallweit , Russell King , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: Eric Woudstra , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH net-next v2 04/10] net: phy: air: type the buckpbus core on the mdio device Date: Fri, 4 Sep 2026 19:02:58 +0000 Message-ID: <9d88227c618e150dae04c386c0dc05992cf9035f.1788548229.git.f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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 buckpbus accessors only need an MDIO device, but they take a phy_device, which ties them to a probed PHY. An upcoming MDIO device driver needs the same register access before any phy_device exists, since it runs precisely to make the PHY presentable. Retype the internal helpers onto an mdio_device and keep the exported phy_device API as page-selecting wrappers that pass &phydev->mdio. The EN8811H driver already reaches the AN8811HB pbus through an mdio_device, so this follows an existing direction rather than opening a new one. No functional change. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- drivers/net/phy/air_phy_lib.c | 80 ++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/drivers/net/phy/air_phy_lib.c b/drivers/net/phy/air_phy_lib.c index 5141db19fa5e..e314717843ae 100644 --- a/drivers/net/phy/air_phy_lib.c +++ b/drivers/net/phy/air_phy_lib.c @@ -14,31 +14,32 @@ =20 #include "air_phy_lib.h" =20 -static int __air_buckpbus_reg_read(struct phy_device *phydev, +static int __air_buckpbus_reg_read(struct mdio_device *mdiodev, u32 pbus_address, u32 *pbus_data) { int pbus_data_low, pbus_data_high; int ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_MODE, + AIR_BPBUS_MODE_ADDR_FIXED); if (ret < 0) return ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, - upper_16_bits(pbus_address)); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_RD_ADDR_HIGH, + upper_16_bits(pbus_address)); if (ret < 0) return ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, - lower_16_bits(pbus_address)); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_RD_ADDR_LOW, + lower_16_bits(pbus_address)); if (ret < 0) return ret; =20 - pbus_data_high =3D __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); + pbus_data_high =3D __mdiodev_read(mdiodev, AIR_BPBUS_RD_DATA_HIGH); if (pbus_data_high < 0) return pbus_data_high; =20 - pbus_data_low =3D __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); + pbus_data_low =3D __mdiodev_read(mdiodev, AIR_BPBUS_RD_DATA_LOW); if (pbus_data_low < 0) return pbus_data_low; =20 @@ -46,64 +47,66 @@ static int __air_buckpbus_reg_read(struct phy_device *p= hydev, return 0; } =20 -static int __air_buckpbus_reg_write(struct phy_device *phydev, +static int __air_buckpbus_reg_write(struct mdio_device *mdiodev, u32 pbus_address, u32 pbus_data) { int ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_MODE, + AIR_BPBUS_MODE_ADDR_FIXED); if (ret < 0) return ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, - upper_16_bits(pbus_address)); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_WR_ADDR_HIGH, + upper_16_bits(pbus_address)); if (ret < 0) return ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, - lower_16_bits(pbus_address)); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_WR_ADDR_LOW, + lower_16_bits(pbus_address)); if (ret < 0) return ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, - upper_16_bits(pbus_data)); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_WR_DATA_HIGH, + upper_16_bits(pbus_data)); if (ret < 0) return ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, - lower_16_bits(pbus_data)); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_WR_DATA_LOW, + lower_16_bits(pbus_data)); if (ret < 0) return ret; =20 return 0; } =20 -static int __air_buckpbus_reg_modify(struct phy_device *phydev, +static int __air_buckpbus_reg_modify(struct mdio_device *mdiodev, u32 pbus_address, u32 mask, u32 set) { int pbus_data_low, pbus_data_high; u32 pbus_data_old, pbus_data_new; int ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_MODE, + AIR_BPBUS_MODE_ADDR_FIXED); if (ret < 0) return ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, - upper_16_bits(pbus_address)); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_RD_ADDR_HIGH, + upper_16_bits(pbus_address)); if (ret < 0) return ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, - lower_16_bits(pbus_address)); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_RD_ADDR_LOW, + lower_16_bits(pbus_address)); if (ret < 0) return ret; =20 - pbus_data_high =3D __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); + pbus_data_high =3D __mdiodev_read(mdiodev, AIR_BPBUS_RD_DATA_HIGH); if (pbus_data_high < 0) return pbus_data_high; =20 - pbus_data_low =3D __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); + pbus_data_low =3D __mdiodev_read(mdiodev, AIR_BPBUS_RD_DATA_LOW); if (pbus_data_low < 0) return pbus_data_low; =20 @@ -112,23 +115,23 @@ static int __air_buckpbus_reg_modify(struct phy_devic= e *phydev, if (pbus_data_new =3D=3D pbus_data_old) return 0; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, - upper_16_bits(pbus_address)); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_WR_ADDR_HIGH, + upper_16_bits(pbus_address)); if (ret < 0) return ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, - lower_16_bits(pbus_address)); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_WR_ADDR_LOW, + lower_16_bits(pbus_address)); if (ret < 0) return ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, - upper_16_bits(pbus_data_new)); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_WR_DATA_HIGH, + upper_16_bits(pbus_data_new)); if (ret < 0) return ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, - lower_16_bits(pbus_data_new)); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_WR_DATA_LOW, + lower_16_bits(pbus_data_new)); if (ret < 0) return ret; =20 @@ -144,7 +147,8 @@ int air_phy_buckpbus_reg_read(struct phy_device *phydev= , u32 pbus_address, saved_page =3D phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); =20 if (saved_page >=3D 0) { - ret =3D __air_buckpbus_reg_read(phydev, pbus_address, pbus_data); + ret =3D __air_buckpbus_reg_read(&phydev->mdio, pbus_address, + pbus_data); if (ret < 0) phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, pbus_address, ret); @@ -163,7 +167,7 @@ int air_phy_buckpbus_reg_write(struct phy_device *phyde= v, u32 pbus_address, saved_page =3D phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); =20 if (saved_page >=3D 0) { - ret =3D __air_buckpbus_reg_write(phydev, pbus_address, + ret =3D __air_buckpbus_reg_write(&phydev->mdio, pbus_address, pbus_data); if (ret < 0) phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, @@ -183,8 +187,8 @@ int air_phy_buckpbus_reg_modify(struct phy_device *phyd= ev, u32 pbus_address, saved_page =3D phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); =20 if (saved_page >=3D 0) { - ret =3D __air_buckpbus_reg_modify(phydev, pbus_address, mask, - set); + ret =3D __air_buckpbus_reg_modify(&phydev->mdio, pbus_address, + mask, set); if (ret < 0) phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, pbus_address, ret); --=20 2.53.0 From nobody Sat Sep 26 03:17:25 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 21FD0424664 for ; Fri, 4 Sep 2026 19:03:16 +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=1788548602; cv=none; b=oCeGi0UjCNMNgvt6IoJ69pXNpWDL+OpjBP448c09pkOkvjLN35GyNirF7pQnY4Ph+lEWpsvhXLxhYbIj5t2RB3IYKJlqhZxSZj5muSDaAN8V0JIgDwINinuGOo6hSHEezONwq8pATBJEk/n3neUF71Q/ze5lf0AMe1VF+CWwfCM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548602; c=relaxed/simple; bh=hlST2y/Nrws+rZfEBBvC+1GEYroutzXg2Z4/JIwBoKU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YThtOD84mbR/t/LlOTvninjGKnuyPfTuASwt7qY73/eKqJYSRlg7R3pup8f28KvtX4lzhYBGnNZvAPzGK5AVEDMllcxn8jnm6iT3Fj9JDnLCoGUhpyB3QuKk9P5LZSLaNHz8O2VhCKo7fWaa4fBjddblvklH29vsbyMQ2NJskxY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la; spf=pass smtp.mailfrom=lex.la; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b=klbb0LW/; arc=none smtp.client-ip=209.85.128.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lex.la Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b="klbb0LW/" Received: by mail-wm1-f42.google.com with SMTP id 5b1f17b1804b1-49b8eeb3ff2so12819315e9.2 for ; Fri, 04 Sep 2026 12:03:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1788548593; x=1789153393; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=j+bsWXVk/02X1VVug4FP/+rrzX5a4PtjmYQgHwQj6uE=; b=klbb0LW/zmJgqtFYLCCHm4Xp6bDS04sv5Mpah7yueiRpPg4hoCZKfH1mplUYsiiXuz IRS8/SY828vauy7Sd4x30WhpUNY1xuw5TV8Jd3wn9fcjsyDQTbsheJoG52vuycpYS/z+ x3xObYiV+EGbQuDTDZ7zeeBMubzA7LZIAMXiWRIcZsEqP2dv4R3L/ftaUEtgaCpVbYTR VODQai0XJgo4UDLPQN6GqCnVfQ/dQeQkQe/XszVkyHmUv1+NHmX7SvKfCy66vqzZpNC0 XkCv/EaefF5rqKEsfzc2yRfVmSN49y+uHfEsOf1/e3ZgnvYvyDlN/DRQIwnTmRkm5eiT Bk8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788548593; x=1789153393; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=j+bsWXVk/02X1VVug4FP/+rrzX5a4PtjmYQgHwQj6uE=; b=S9kHTxilyDGIThwsRoDqA1roElfYeGqQCz1IQTdJ6s+wG8oAQVa16wmOcsfpv66rB2 qxA2ODvRuUiJVN2j2rKVYiE6kEWx8qSMw0UZh2vmApcJY1Btz08qxcPrQ0yNmR+4vHjF hCdOzjFEG87PiyBmYIKiWQCGN2p5+CuzlPNxojbvrJl/4IcoPjJSneQ+5Lb3njnRBnSv Mz+D1wHkMRumvwyAuWVOr9BTTSLuoX3cPXI8Kc/mYG4NpNlzrdcp4d8vHiONCJStJD1r 1Fp/Tpo5/3o7FKzYYhMZZ2GS7CMfjZMCdy1CKoDbwRi7oxbZ0WQMsytXKOjXPj6VVO+e KdBg== X-Forwarded-Encrypted: i=1; AKwUvBzWJWlkEMl8KFoY0wBTUhwBiWoRtRbTIKnuazn3ce6RxXmLze5tCt7Z/4gn9q7OMff9eqdnMnq7TF/Tt1s=@vger.kernel.org X-Gm-Message-State: AFuF++mWIozPX5ci9b+u+Awwm91QLBl20ctjH4jgxUSx3ScfqXdnAsGp ge4yEUlnlG9VYG6NiVrVJhB7mY9HWI7WwpmiBwMC4aKyIMApqmgIaU/wJt0VvVkFtNU= X-Gm-Gg: AYBFou2FCLnQtJ6Or67NXqz39v24wdEewcckxPgGmToB04wYkOBc9csOa1ChXwbeRlc 54BSC43U+zIv+68b4FR8R0HHHdgh2rpd8bVh0f35I/kvQlBa+XtjslWbuGePJXzo5m6fAJoqbSi jJW/9CE8n8tx9i5ACy/cahMgVyjafE8LmmHEMWCC1D3TJUiWCnSpDuavKPtLYMkO0RYh3azoWSN hvsdQBD6IWhuUwdi73b5lyiORw9yUiybCImi3oITVeLcnGpMt6vsXwWYA+eJ8bu+vbhQhBEQBB7 fw5FMUSuZiDrB72yHk79BkMgEJPQnjgouCg71h50OmOuo/154XUmLwyl0BH/KUxQ+q9AcI1twx0 N2kwELlbCN/Z1P0TxU3UFVtwX5RmFkSxwRNQGrWdgoX1yE1q8i4P/RRCeYTgSHOwfIwjKqlJVM+ c5Q/dKfCFAMGzjCy8XVILvQqZmmHWI/RlGiGPNTSw= X-Received: by 2002:a05:600c:1551:b0:49c:fa21:e73e with SMTP id 5b1f17b1804b1-49cfa21e935mr64950255e9.20.1788548593446; Fri, 04 Sep 2026 12:03:13 -0700 (PDT) Received: from remote-01 ([84.17.55.227]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49cee60d8a6sm172195485e9.10.2026.09.04.12.03.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2026 12:03:13 -0700 (PDT) From: Aleksei Sviridkin To: Andrew Lunn , Andrew Lunn , Heiner Kallweit , Russell King , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: Eric Woudstra , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH net-next v2 05/10] net: phy: air: move the EN8811H firmware download into the library Date: Fri, 4 Sep 2026 19:02:59 +0000 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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 EN8811H firmware loader is welded to the PHY driver, but the next patch adds an MDIO device driver that must perform the same download before any phy_device exists. Move the download engine into the shared library, typed on the MDIO device like the buckpbus core. The moved helpers take the bus lock and save and restore the page register themselves, since phy_select_page() needs a phy_device. The status poll now asks for the MMD register through the Clause 22 indirection unconditionally. phy_read_mmd() used to resolve that from phydev->is_c45, which is false for every device tree describing the Clause 22 PHYs this library serves, so hardcoding it changes nothing any board runs today. The version read at the end is now checked. en8811h_print_fw_version() threw its result away, so a bus error there left the version at zero and let probe continue; the load fails instead. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- drivers/net/phy/air_en8811h.c | 139 +----------------- drivers/net/phy/air_phy_lib.c | 260 ++++++++++++++++++++++++++++++++++ drivers/net/phy/air_phy_lib.h | 24 ++++ 3 files changed, 288 insertions(+), 135 deletions(-) diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c index 38eb18f0e9bb..2f6ed30ba24d 100644 --- a/drivers/net/phy/air_en8811h.c +++ b/drivers/net/phy/air_en8811h.c @@ -20,21 +20,15 @@ #include #include #include -#include =20 #include "air_phy_lib.h" =20 #define EN8811H_PHY_ID 0x03a2a411 #define AN8811HB_PHY_ID 0xc0ff04a0 =20 -#define EN8811H_MD32_DM "airoha/EthMD32.dm.bin" -#define EN8811H_MD32_DSP "airoha/EthMD32.DSP.bin" #define AN8811HB_MD32_DM "airoha/an8811hb/EthMD32_CRC.DM.bin" #define AN8811HB_MD32_DSP "airoha/an8811hb/EthMD32_CRC.DSP.bin" =20 -#define AIR_FW_ADDR_DM 0x00000000 -#define AIR_FW_ADDR_DSP 0x00100000 - /* MII Registers */ #define AIR_AUX_CTRL_STATUS 0x1d #define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2) @@ -44,8 +38,6 @@ #define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc =20 /* Registers on MDIO_MMD_VEND1 */ -#define EN8811H_PHY_FW_STATUS 0x8009 -#define EN8811H_PHY_READY 0x02 =20 #define AIR_PHY_MCU_CMD_0 0x800b #define AIR_PHY_MCU_CMD_1 0x800c @@ -108,8 +100,6 @@ #define EN8811H_2P5G_LPA 0x3b30 #define EN8811H_2P5G_LPA_2P5G BIT(0) =20 -#define EN8811H_FW_VERSION 0x3b3c - #define EN8811H_POLARITY 0xca0f8 #define EN8811H_POLARITY_TX_NORMAL BIT(0) #define EN8811H_POLARITY_RX_REVERSE BIT(1) @@ -122,12 +112,6 @@ #define EN8811H_CLK_CGM 0xcf958 #define EN8811H_CLK_CGM_CKO BIT(26) =20 -#define EN8811H_FW_CTRL_1 0x0f0018 -#define EN8811H_FW_CTRL_1_START 0x0 -#define EN8811H_FW_CTRL_1_FINISH 0x1 -#define EN8811H_FW_CTRL_2 0x800000 -#define EN8811H_FW_CTRL_2_LOADING BIT(11) - #define AN8811HB_CRC_PM_SET1 0xf020c #define AN8811HB_CRC_PM_MON2 0xf0218 #define AN8811HB_CRC_PM_MON3 0xf021c @@ -270,80 +254,9 @@ static int __air_pbus_reg_write(struct mdio_device *md= iodev, upper_16_bits(pbus_data)); } =20 -static int __air_write_buf(struct phy_device *phydev, u32 address, - const struct firmware *fw) -{ - unsigned int offset; - int ret; - u16 val; - - ret =3D __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_INCR); - if (ret < 0) - return ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, - upper_16_bits(address)); - if (ret < 0) - return ret; - - ret =3D __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, - lower_16_bits(address)); - if (ret < 0) - return ret; - - for (offset =3D 0; offset < fw->size; offset +=3D 4) { - val =3D get_unaligned_le16(&fw->data[offset + 2]); - ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, val); - if (ret < 0) - return ret; - - val =3D get_unaligned_le16(&fw->data[offset]); - ret =3D __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, val); - if (ret < 0) - return ret; - } - - return 0; -} - -static int air_write_buf(struct phy_device *phydev, u32 address, - const struct firmware *fw) -{ - int saved_page; - int ret =3D 0; - - saved_page =3D phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); - - if (saved_page >=3D 0) { - ret =3D __air_write_buf(phydev, address, fw); - if (ret < 0) - phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, - address, ret); - } - - return phy_restore_page(phydev, saved_page, ret); -} - static int en8811h_wait_mcu_ready(struct phy_device *phydev) { - int ret, reg_value; - - ret =3D air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_FINISH); - if (ret) - return ret; - - /* Because of mdio-lock, may have to wait for multiple loads */ - ret =3D phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, - EN8811H_PHY_FW_STATUS, reg_value, - reg_value =3D=3D EN8811H_PHY_READY, - 20000, 7500000, true); - if (ret) { - phydev_err(phydev, "MCU not ready: 0x%x\n", reg_value); - return -ENODEV; - } - - return 0; + return air_en8811h_wait_mcu_ready(&phydev->mdio); } =20 static int an8811hb_check_crc(struct phy_device *phydev, u32 set1, @@ -405,7 +318,7 @@ static int an8811hb_load_file(struct phy_device *phydev= , const char *name, if (ret < 0) return ret; =20 - ret =3D air_write_buf(phydev, address, fw); + ret =3D air_fw_write_buf(&phydev->mdio, address, fw); release_firmware(fw); return ret; } @@ -501,54 +414,10 @@ static int an8811hb_load_firmware(struct phy_device *= phydev) =20 static int en8811h_load_firmware(struct phy_device *phydev) { - struct device *dev =3D &phydev->mdio.dev; - const struct firmware *fw1, *fw2; + struct en8811h_priv *priv =3D phydev->priv; int ret; =20 - ret =3D request_firmware_direct(&fw1, EN8811H_MD32_DM, dev); - if (ret < 0) - return ret; - - ret =3D request_firmware_direct(&fw2, EN8811H_MD32_DSP, dev); - if (ret < 0) - goto en8811h_load_firmware_rel1; - - ret =3D air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_START); - if (ret < 0) - goto en8811h_load_firmware_out; - - ret =3D air_phy_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, - EN8811H_FW_CTRL_2_LOADING, - EN8811H_FW_CTRL_2_LOADING); - if (ret < 0) - goto en8811h_load_firmware_out; - - ret =3D air_write_buf(phydev, AIR_FW_ADDR_DM, fw1); - if (ret < 0) - goto en8811h_load_firmware_out; - - ret =3D air_write_buf(phydev, AIR_FW_ADDR_DSP, fw2); - if (ret < 0) - goto en8811h_load_firmware_out; - - ret =3D air_phy_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, - EN8811H_FW_CTRL_2_LOADING, 0); - if (ret < 0) - goto en8811h_load_firmware_out; - - ret =3D en8811h_wait_mcu_ready(phydev); - if (ret < 0) - goto en8811h_load_firmware_out; - - en8811h_print_fw_version(phydev); - -en8811h_load_firmware_out: - release_firmware(fw2); - -en8811h_load_firmware_rel1: - release_firmware(fw1); - + ret =3D air_en8811h_fw_download(&phydev->mdio, &priv->firmware_version); if (ret < 0) phydev_err(phydev, "Load firmware failed: %d\n", ret); =20 diff --git a/drivers/net/phy/air_phy_lib.c b/drivers/net/phy/air_phy_lib.c index e314717843ae..2f3e5b71abac 100644 --- a/drivers/net/phy/air_phy_lib.c +++ b/drivers/net/phy/air_phy_lib.c @@ -8,11 +8,16 @@ */ =20 #include +#include +#include +#include #include #include +#include #include =20 #include "air_phy_lib.h" +#include "phylib.h" =20 static int __air_buckpbus_reg_read(struct mdio_device *mdiodev, u32 pbus_address, u32 *pbus_data) @@ -198,6 +203,261 @@ int air_phy_buckpbus_reg_modify(struct phy_device *ph= ydev, u32 pbus_address, } EXPORT_SYMBOL_GPL(air_phy_buckpbus_reg_modify); =20 +static int __air_write_buf(struct mdio_device *mdiodev, u32 address, + const struct firmware *fw) +{ + unsigned int offset; + int ret; + u16 val; + + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_MODE, + AIR_BPBUS_MODE_ADDR_INCR); + if (ret < 0) + return ret; + + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_WR_ADDR_HIGH, + upper_16_bits(address)); + if (ret < 0) + return ret; + + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_WR_ADDR_LOW, + lower_16_bits(address)); + if (ret < 0) + return ret; + + for (offset =3D 0; offset < fw->size; offset +=3D 4) { + val =3D get_unaligned_le16(&fw->data[offset + 2]); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_WR_DATA_HIGH, val); + if (ret < 0) + return ret; + + val =3D get_unaligned_le16(&fw->data[offset]); + ret =3D __mdiodev_write(mdiodev, AIR_BPBUS_WR_DATA_LOW, val); + if (ret < 0) + return ret; + } + + return 0; +} + +/* phy_select_page() needs a phy_device, which does not exist yet. */ +static int __air_mdio_select_page(struct mdio_device *mdiodev, int page) +{ + int saved_page, ret; + + saved_page =3D __mdiodev_read(mdiodev, AIR_EXT_PAGE_ACCESS); + if (saved_page < 0) + return saved_page; + + if (saved_page !=3D page) { + ret =3D __mdiodev_write(mdiodev, AIR_EXT_PAGE_ACCESS, page); + if (ret < 0) + return ret; + } + + return saved_page; +} + +static int __air_mdio_restore_page(struct mdio_device *mdiodev, + int saved_page, int page, int ret) +{ + int restore; + + if (saved_page !=3D page) { + restore =3D __mdiodev_write(mdiodev, AIR_EXT_PAGE_ACCESS, + saved_page); + if (ret >=3D 0 && restore < 0) + ret =3D restore; + } + + return ret; +} + +int air_fw_write_buf(struct mdio_device *mdiodev, u32 address, + const struct firmware *fw) +{ + int saved_page, ret; + + mdiodev_lock(mdiodev); + + saved_page =3D __air_mdio_select_page(mdiodev, AIR_PHY_PAGE_EXTENDED_4); + if (saved_page < 0) { + ret =3D saved_page; + } else { + ret =3D __air_write_buf(mdiodev, address, fw); + ret =3D __air_mdio_restore_page(mdiodev, saved_page, + AIR_PHY_PAGE_EXTENDED_4, ret); + } + + mdiodev_unlock(mdiodev); + return ret; +} +EXPORT_SYMBOL_GPL(air_fw_write_buf); + +static int air_mdio_buckpbus_reg_read(struct mdio_device *mdiodev, + u32 pbus_address, u32 *pbus_data) +{ + int saved_page, ret; + + mdiodev_lock(mdiodev); + + saved_page =3D __air_mdio_select_page(mdiodev, AIR_PHY_PAGE_EXTENDED_4); + if (saved_page < 0) { + ret =3D saved_page; + } else { + ret =3D __air_buckpbus_reg_read(mdiodev, pbus_address, pbus_data); + ret =3D __air_mdio_restore_page(mdiodev, saved_page, + AIR_PHY_PAGE_EXTENDED_4, ret); + } + + mdiodev_unlock(mdiodev); + return ret; +} + +static int air_mdio_buckpbus_reg_write(struct mdio_device *mdiodev, + u32 pbus_address, u32 pbus_data) +{ + int saved_page, ret; + + mdiodev_lock(mdiodev); + + saved_page =3D __air_mdio_select_page(mdiodev, AIR_PHY_PAGE_EXTENDED_4); + if (saved_page < 0) { + ret =3D saved_page; + } else { + ret =3D __air_buckpbus_reg_write(mdiodev, pbus_address, + pbus_data); + ret =3D __air_mdio_restore_page(mdiodev, saved_page, + AIR_PHY_PAGE_EXTENDED_4, ret); + } + + mdiodev_unlock(mdiodev); + return ret; +} + +static int air_mdio_buckpbus_reg_modify(struct mdio_device *mdiodev, + u32 pbus_address, u32 mask, u32 set) +{ + int saved_page, ret; + + mdiodev_lock(mdiodev); + + saved_page =3D __air_mdio_select_page(mdiodev, AIR_PHY_PAGE_EXTENDED_4); + if (saved_page < 0) { + ret =3D saved_page; + } else { + ret =3D __air_buckpbus_reg_modify(mdiodev, pbus_address, + mask, set); + ret =3D __air_mdio_restore_page(mdiodev, saved_page, + AIR_PHY_PAGE_EXTENDED_4, ret); + } + + mdiodev_unlock(mdiodev); + return ret; +} + +static int air_mmd_status_read(struct mdio_device *mdiodev) +{ + int ret; + + mdiodev_lock(mdiodev); + ret =3D mmd_phy_read(mdiodev->bus, mdiodev->addr, false, + MDIO_MMD_VEND1, EN8811H_PHY_FW_STATUS); + mdiodev_unlock(mdiodev); + + return ret; +} + +int air_en8811h_wait_mcu_ready(struct mdio_device *mdiodev) +{ + int ret, reg_value; + + ret =3D air_mdio_buckpbus_reg_write(mdiodev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_FINISH); + if (ret) + return ret; + + /* Because of mdio-lock, may have to wait for multiple loads. A read + * error ends the poll at once, like phy_read_mmd_poll_timeout() + * would: the bus is not going to heal within the timeout. + */ + ret =3D read_poll_timeout(air_mmd_status_read, reg_value, + reg_value < 0 || + reg_value =3D=3D EN8811H_PHY_READY, + 20000, 7500000, true, mdiodev); + if (reg_value < 0) + return reg_value; + if (ret) { + dev_err(&mdiodev->dev, "MCU not ready: 0x%x\n", reg_value); + return -ENODEV; + } + + return 0; +} +EXPORT_SYMBOL_GPL(air_en8811h_wait_mcu_ready); + +int air_en8811h_fw_download(struct mdio_device *mdiodev, u32 *fw_version) +{ + const struct firmware *fw1, *fw2; + struct device *dev =3D &mdiodev->dev; + int ret; + + ret =3D request_firmware_direct(&fw1, EN8811H_MD32_DM, dev); + if (ret < 0) + return ret; + + ret =3D request_firmware_direct(&fw2, EN8811H_MD32_DSP, dev); + if (ret < 0) + goto air_fw_download_rel1; + + ret =3D air_mdio_buckpbus_reg_write(mdiodev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_START); + if (ret < 0) + goto air_fw_download_out; + + ret =3D air_mdio_buckpbus_reg_modify(mdiodev, EN8811H_FW_CTRL_2, + EN8811H_FW_CTRL_2_LOADING, + EN8811H_FW_CTRL_2_LOADING); + if (ret < 0) + goto air_fw_download_out; + + ret =3D air_fw_write_buf(mdiodev, AIR_FW_ADDR_DM, fw1); + if (ret < 0) + goto air_fw_download_out; + + ret =3D air_fw_write_buf(mdiodev, AIR_FW_ADDR_DSP, fw2); + if (ret < 0) + goto air_fw_download_out; + + ret =3D air_mdio_buckpbus_reg_modify(mdiodev, EN8811H_FW_CTRL_2, + EN8811H_FW_CTRL_2_LOADING, 0); + if (ret < 0) + goto air_fw_download_out; + + ret =3D air_en8811h_wait_mcu_ready(mdiodev); + if (ret < 0) + goto air_fw_download_out; + + ret =3D air_mdio_buckpbus_reg_read(mdiodev, EN8811H_FW_VERSION, + fw_version); + if (ret < 0) + goto air_fw_download_out; + + dev_info(dev, "MD32 firmware version: %08x\n", *fw_version); + +air_fw_download_out: + release_firmware(fw2); + +air_fw_download_rel1: + release_firmware(fw1); + + /* No error print: callers log on their own terms, and a poller + * would repeat it on every retry. + */ + return ret; +} +EXPORT_SYMBOL_GPL(air_en8811h_fw_download); + int air_phy_read_page(struct phy_device *phydev) { return __phy_read(phydev, AIR_EXT_PAGE_ACCESS); diff --git a/drivers/net/phy/air_phy_lib.h b/drivers/net/phy/air_phy_lib.h index 01bb32e7c7c9..2a4c156d6396 100644 --- a/drivers/net/phy/air_phy_lib.h +++ b/drivers/net/phy/air_phy_lib.h @@ -29,6 +29,23 @@ #define AIR_BPBUS_RD_DATA_HIGH 0x17 #define AIR_BPBUS_RD_DATA_LOW 0x18 =20 +#define EN8811H_MD32_DM "airoha/EthMD32.dm.bin" +#define EN8811H_MD32_DSP "airoha/EthMD32.DSP.bin" + +#define AIR_FW_ADDR_DM 0x00000000 +#define AIR_FW_ADDR_DSP 0x00100000 + +#define EN8811H_FW_CTRL_1 0x0f0018 +#define EN8811H_FW_CTRL_1_START 0x0 +#define EN8811H_FW_CTRL_1_FINISH 0x1 +#define EN8811H_FW_CTRL_2 0x800000 +#define EN8811H_FW_CTRL_2_LOADING BIT(11) + +#define EN8811H_PHY_FW_STATUS 0x8009 +#define EN8811H_PHY_READY 0x02 + +#define EN8811H_FW_VERSION 0x3b3c + int air_phy_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_addres= s, u32 mask, u32 set); int air_phy_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address, @@ -38,4 +55,11 @@ int air_phy_buckpbus_reg_write(struct phy_device *phydev= , u32 pbus_address, int air_phy_read_page(struct phy_device *phydev); int air_phy_write_page(struct phy_device *phydev, int page); =20 +struct firmware; + +int air_fw_write_buf(struct mdio_device *mdiodev, u32 address, + const struct firmware *fw); +int air_en8811h_wait_mcu_ready(struct mdio_device *mdiodev); +int air_en8811h_fw_download(struct mdio_device *mdiodev, u32 *fw_version); + #endif /* __AIR_PHY_LIB_H */ --=20 2.53.0 From nobody Sat Sep 26 03:17:25 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 24A09374730 for ; Fri, 4 Sep 2026 19:03:18 +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=1788548607; cv=none; b=T0bgTLyUogW5j7NZD4tKYZXDYsGczdTto5Q1kokl1BMM2gkFVk0kPJqPn6ouNFVRrX8IYG+lHCRou45MU5fXL92VUyAEb2rNpzyDMNznVOM5241yqZP4EKDLKlydkHrCejyvagrCEHXysZxsF4QhIDoUwt1Szq8yiKv5KvRKLVQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548607; c=relaxed/simple; bh=tvwBi/oKJVRvzD1Ea9uSmVR/d+BAWrIijfyOV4a7Zv0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=c1AK2Ay826goj1sJPdmmI/t2R1Id9EtLFSaVmnhU/imABJwFKbfwPTPwfFfXlG3fkMOEBnr/rIUPGrgupOO+jefwyVqXp4btvgfWlA+yQyipVGFCorA49ylHp1zc0BXc1w+D3B9ogTmngOqTrwKUNID8AQiuIpeS3GbUmaA7Nbk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la; spf=pass smtp.mailfrom=lex.la; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b=IwvbzE9r; arc=none smtp.client-ip=209.85.128.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lex.la Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b="IwvbzE9r" Received: by mail-wm1-f42.google.com with SMTP id 5b1f17b1804b1-49ccfae359fso11358705e9.3 for ; Fri, 04 Sep 2026 12:03:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1788548595; x=1789153395; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=spwFfBNp0tsbFO0MbVx5HsS6oEJ6iTQA15tu/YnOvzo=; b=IwvbzE9rh4h+G5V7of0i08GFEZX9/r3kyfdE0hnv8/Ren4+JE0V9ThGqh8mUTMEvxH 75FDQOWkY2n9jz1RPk56SHbWiE9xNy4wLfbwO9GhOoTuAiTWSpwJigb0gn1GlWUHuhH2 YB2CQXxyQPaoDCfkR5EbPD/ZSQsg7mG6BGMsxd/HvmCf6HudZudAidtL4gATW7E/Y5Yg P5RYd83dmqs6HIzRgRGja3mIXO2tl5xqTFUJGfN5yFH+SndgvgQoELYg7nup4Sd4jThC Z9iYepDQzTso+ltf+FRn1sgnT0fbWHkiczi4c64So+Tsfpzbg/V6YjQD8Z1C24DRcRn1 oQqg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788548595; x=1789153395; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=spwFfBNp0tsbFO0MbVx5HsS6oEJ6iTQA15tu/YnOvzo=; b=GOweQsct3nJzUM+qNDj64G86qap1vrx/C2Nxkv/FtNV6Oy/0zy+sv8SqqrowGGIwWi uh5FT3edQnrtxdWjE8GYban657J9Gli4CbQgGbPeTNx28NFpMPktVua//awak3u24vEx r6XCNyipVD3UYIhpOscuhP/o0I+Ocy7Dk0wc1GfBMwLZFZ4elQxFRozfeuIFv7Nns+Z7 frVZ2cTiDqE8nWIrZPdKzHNbA3+F5qbDG87dXCQ5oweqOkZP3mzgRL9IlYH7mntroJeT 22thbhlVDgFa/i9ecBA2yFeJKxMP1tyGDcJkg5UdG/iqxXRgf0qf0ScFZKepmgl55sHO 5Uvw== X-Forwarded-Encrypted: i=1; AKwUvByUGzZAKk/i7HeCvPLPRNifgGD41F+Upga2MFz26gpl42bV9nGjeeI/j3IQ6QhSEbGXKxnqkYlkcUWALzQ=@vger.kernel.org X-Gm-Message-State: AFuF++nDbE+4YQdf9q1S7v5LjeWnykrC1WNeISskunYg7N1qMC8JxsrI Yg25tAWQohXod6QSvPhhS6i4va1dBBIQ6Jcpceo/DvwPG2p54oxWzfOe+NHJ2bjkpKI= X-Gm-Gg: AYBFou2jdN8hQqCF1DVYigiJhxVPHJD5OIrOAWoXcbn9bxic3ILFFqoLw6dBYscA3dC gndjoKaHhZXoi9/8ghr7Sp2u/ra6x6uXJud+vO4j65EmT5CT8xCRj2622/a9X+04mYtXJqwjm37 T3et1b6ZbnAm0iWw69lf/3kNzdsM0MmdEIWCnpf8IIXOoX0tNITUASOMV/wgG50oAjI9M054fZw KPELA3bzV90U2I+7Y+JL3VWxrDiET6sljIbg3V7HmJ6aNOx6swbRfdKDOWnJsb1SbMn2wgRmwCb PIF98kQrlbdbRvTcx5fIr6qy5OSgHbYtXpSltv8wz7b4LJVd3WYA7TOYDlAFBhafkM+JC6d/bRj Wa4KX5ySgqDlCGsUTQ2vi4U434R4HskL/RWvM/3Kb2lcBVmy4VF6gbqnb7egjmjMI9uBsEJ0WBP w9Zz5xRISCpf5uP9vGau4vQUOtvMG85t2+OOjora0VkmIC/RK3XOY= X-Received: by 2002:a05:600c:35c3:b0:49c:fc6c:be10 with SMTP id 5b1f17b1804b1-49cfc6cc055mr52700515e9.22.1788548594795; Fri, 04 Sep 2026 12:03:14 -0700 (PDT) Received: from remote-01 ([84.17.55.227]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49cee60d8a6sm172195485e9.10.2026.09.04.12.03.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2026 12:03:14 -0700 (PDT) From: Aleksei Sviridkin To: Andrew Lunn , Andrew Lunn , Heiner Kallweit , Russell King , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: Eric Woudstra , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH net-next v2 06/10] net: phy: air: skip the download when the MD32 is already running Date: Fri, 4 Sep 2026 19:03:00 +0000 Message-ID: <0eb669e919da337cbc456b7aecd06e6d9509ad17.1788548229.git.f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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 download is unconditional, so a chip whose firmware was loaded by something else - a bootloader, an earlier bind of the PHY driver, or an MDIO device serving the chip - is reprogrammed at 144KB per probe. Read the status register the loader already polls for readiness and skip the download when it reports ready, only picking up the running firmware's version. Adopting is reported back distinctly from loading, because nothing on that path touches FW_CTRL_1: the PHY driver must leave the MCU restart to .config_init() rather than assume probe already did it. The image in RAM now wins over the files on disk. Where the PHY node carries no reset-gpios nothing clears that RAM on unbind, so writing new firmware files and rebinding keeps the old image running and reports its version as the current one. A power cycle, or a reset line on the PHY node for phy_detach() to assert, brings the reload back. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- drivers/net/phy/air_en8811h.c | 4 ++-- drivers/net/phy/air_phy_lib.c | 17 +++++++++++++++++ drivers/net/phy/air_phy_lib.h | 2 ++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c index 2f6ed30ba24d..51ff90e60c25 100644 --- a/drivers/net/phy/air_en8811h.c +++ b/drivers/net/phy/air_en8811h.c @@ -1019,8 +1019,8 @@ static int en8811h_probe(struct phy_device *phydev) if (ret < 0) return ret; =20 - /* mcu has just restarted after firmware load */ - priv->mcu_needs_restart =3D false; + /* Adopted firmware was never restarted here. */ + priv->mcu_needs_restart =3D (ret =3D=3D 1); =20 /* MDIO_DEVS1/2 empty, so set mmds_present bits here */ phydev->c45_ids.mmds_present |=3D MDIO_DEVS_PMAPMD | MDIO_DEVS_AN; diff --git a/drivers/net/phy/air_phy_lib.c b/drivers/net/phy/air_phy_lib.c index 2f3e5b71abac..fc596942eb65 100644 --- a/drivers/net/phy/air_phy_lib.c +++ b/drivers/net/phy/air_phy_lib.c @@ -368,6 +368,12 @@ static int air_mmd_status_read(struct mdio_device *mdi= odev) return ret; } =20 +bool air_en8811h_mcu_running(struct mdio_device *mdiodev) +{ + return air_mmd_status_read(mdiodev) =3D=3D EN8811H_PHY_READY; +} +EXPORT_SYMBOL_GPL(air_en8811h_mcu_running); + int air_en8811h_wait_mcu_ready(struct mdio_device *mdiodev) { int ret, reg_value; @@ -402,6 +408,17 @@ int air_en8811h_fw_download(struct mdio_device *mdiode= v, u32 *fw_version) struct device *dev =3D &mdiodev->dev; int ret; =20 + if (air_en8811h_mcu_running(mdiodev)) { + ret =3D air_mdio_buckpbus_reg_read(mdiodev, EN8811H_FW_VERSION, + fw_version); + if (ret < 0) + return ret; + + dev_info(dev, "MD32 already running, firmware %08x\n", + *fw_version); + return 1; + } + ret =3D request_firmware_direct(&fw1, EN8811H_MD32_DM, dev); if (ret < 0) return ret; diff --git a/drivers/net/phy/air_phy_lib.h b/drivers/net/phy/air_phy_lib.h index 2a4c156d6396..6823812c8fd5 100644 --- a/drivers/net/phy/air_phy_lib.h +++ b/drivers/net/phy/air_phy_lib.h @@ -59,7 +59,9 @@ struct firmware; =20 int air_fw_write_buf(struct mdio_device *mdiodev, u32 address, const struct firmware *fw); +bool air_en8811h_mcu_running(struct mdio_device *mdiodev); int air_en8811h_wait_mcu_ready(struct mdio_device *mdiodev); +/* Returns 1 when it adopted firmware that was already running. */ int air_en8811h_fw_download(struct mdio_device *mdiodev, u32 *fw_version); =20 #endif /* __AIR_PHY_LIB_H */ --=20 2.53.0 From nobody Sat Sep 26 03:17:25 2026 Received: from mail-wm1-f50.google.com (mail-wm1-f50.google.com [209.85.128.50]) (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 5C38A51E420 for ; Fri, 4 Sep 2026 19:03:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548605; cv=none; b=ldq9qcS6xFo80j7eYawtWtwuBb3x9JTwyEWgJOLH2v45SGkjQxYLyOK9VCucnHsoOE1CsbKplt03aMr5Nmt5aP7ld586fsouJDPiO+1i2Hmb6yEXALNMfVUkyfAqjkQUrbC6FQT7jnVHGq2SbnwtQL66jnZQ0GAjIdT1hP/ng3E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548605; c=relaxed/simple; bh=TvmNZ9HIJUKKHCevEGQssxkyOTUK9Y/loRcLTRaueq4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LSc5pYuUKOcRuCrh4ObR+YgKY13gPr6l3DaEKfgJwQc5T8e6WFgv4W+OMy4bZYXE536/n8XSy6IjntaRXczBsbWs0US8O3+awKz4fLPp+kBrir9ciosWuXkx3so4Vm42mLEN9tjajqVG7stvRVa9MHjWsQ6IvBxHKNZsfAXvU4c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la; spf=pass smtp.mailfrom=lex.la; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b=SB21ioUz; arc=none smtp.client-ip=209.85.128.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lex.la Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b="SB21ioUz" Received: by mail-wm1-f50.google.com with SMTP id 5b1f17b1804b1-49b965570d7so15620235e9.0 for ; Fri, 04 Sep 2026 12:03:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1788548596; x=1789153396; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=RNxSPYrqovDI7t4DpXzHkhI1wWnUmO156W7Ben/xlVc=; b=SB21ioUzboW+Kdj9yoks0tS3FgXgnTig2SurLTXAvJh4G9tXQ+24+GscT32zeNwu3J n9Pzu/munStI6d5Yo+q67Mb7l5iwDk9gxE7yH8orGnrUH5re24mfWT0PAIGKxX3gHL69 LfatcvBLRTWGkao/8sPOP+v4dBtAsTA14cqxCtI6lBmM9IKX9nrRGaOgUPv8ZLLxoxgZ DfDVe/SRNKRDl8HlobBxOypQoP6PcJNC7b5J08XgWxEcsi3e/yvJ0H5AqHzUZnolFcPB MLbEZWyTJIyfm6TMWjLgPKCeR4TGI12SKxYKx42DGi2oRmYvSyRLG1+qly7Upl5gPlJF 0pwA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788548596; x=1789153396; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=RNxSPYrqovDI7t4DpXzHkhI1wWnUmO156W7Ben/xlVc=; b=Iws4YBSWedxGyqWNqtN7dggHyRtYf+BEo21F1PdqeMPR5lbZ3j2RdXb5SUVZ+NX7SD jc8QsyWdmadVFkvkkMYgp+f5hL0Nk9dhpxGbUS/MMO4/0GtdSKM80S9Xzby/T8Qj9KJF DAk1LpHr94gJRabqkONGAi+OYY9sa7Gg8Pxq6sKE8tE6ioognL43cQ8E6Ls1TAz6+eip BTg+pdVs1ro2HgkAyEzvQpHquUpORZF0gIX5lRGXA1W0xXYIGV+4oSwvTVxOQom4o12i 8fgxQSYMCthu5iXY1PMG/BwK4SlrdN7b5flEwnmjpzpctf/Gq2E9U2RFjWIHFrzzEqZT UNkA== X-Forwarded-Encrypted: i=1; AKwUvBysjpY0OFBaDKg4nNjx2LESCO1a/eUgh89uiW7oumW5PffwBhsNrtbViKcYH/7/ljsCaTMjwc5fNo0gCnI=@vger.kernel.org X-Gm-Message-State: AFuF++l0/+S9DFYQyLwGQ75wgk7cDIKZvwphbNUKyeYAQF25EdunXtuO Libpe9RBDjmRcI4OlXMzXdFzsLfFg1aBfRUP0lizw3DuygNXtdb0yFjpB0dPJMZReaM= X-Gm-Gg: AYBFou17xajQmm5vJZlkM07I8ETGoorGqJ2gkh9E4Li8kKgLPkbj5IALkU9kqdRydrE 9T7qQfjqwEqqMT9bLVLuHvF6aY0r5xhF6PnZkSseY8FUJAZDMDj4FiEfer5qCDogkfUP1cAwK4H VQX3BR2wPVM3wrkbLj2MAfNWlx5npzjKZdq14BoAmhnaGWQrAd7voJHnO8XjMqjKBAqY47Ie8yl eVNqtMqNVut0vuvNeJFmgGtZVcwMmpS+lOkqwTFLKRl/ASfk0wJOQ0VQ9JrurQrvayfVerJtbHx sELWknNIahpqR8y8KpaZ9mdUeYB0EGX9bgD2uzbWG3Z0UMZj0n4GS8SLsZ000y3h6vO+VHyA55a CpVGa2BmDqNCkCULkef/FvdwjaBQtXXNKv20LHXZ7JYJRzuzYmu/c8mpLSJBGSeVPBDBoYJAl60 dpdCY09LH7JxcNtVCCAKr4seM95FVSjdrSKU/1Ef0= X-Received: by 2002:a05:600c:34c9:b0:49c:f729:d757 with SMTP id 5b1f17b1804b1-49cf824f757mr87221345e9.11.1788548596255; Fri, 04 Sep 2026 12:03:16 -0700 (PDT) Received: from remote-01 ([84.17.55.227]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49cee60d8a6sm172195485e9.10.2026.09.04.12.03.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2026 12:03:15 -0700 (PDT) From: Aleksei Sviridkin To: Andrew Lunn , Andrew Lunn , Heiner Kallweit , Russell King , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: Eric Woudstra , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH net-next v2 07/10] net: mdio: add Airoha EN8811H MDIO device driver Date: Fri, 4 Sep 2026 19:03:01 +0000 Message-ID: <886ca87eb45b4dc94c6542dd80ce23dc76cfbf1c.1788548229.git.f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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" Until its firmware has been downloaded the EN8811H is not an Ethernet PHY, it is an MD32 microcontroller waiting in its bootloader. On systems that keep the firmware files in a filesystem, the files become readable long after the MDIO bus was scanned, and the PHY driver's probe-time download then cannot work at boot. Describe the chip as an MDIO device that polls for the files and downloads through the shared library helper once they can be read; a chip left running by the bootloader is adopted as-is. Polling rather than deferred probing because request_firmware_direct() has no usermode-helper fallback: an unmounted rootfs fails at once and would keep the deferred-probe list spinning for the whole mount window. There is no give-up path, since installing the firmware package on a running system is a normal thing to do. The stall warning is gated on a per-device flag rather than dev_warn_once(), which is per call site: a board can carry two of these chips. The reset line is claimed here rather than on the PHY node, and it is cycled only while the MD32 does not report a running firmware: that firmware lives in volatile RAM, so an assert on a running chip - such as the one phy_detach() performs on a PHY-node reset - would wipe it. The chip's MDIO slave implements the Clause 22 MMD indirection and the firmware data path is pure Clause 22 by design, so the library reaches the status register the same way. That poll is one register read behind three address writes, where the indirection costs nothing measurable, and whether the chip decodes Clause 45 frames before its firmware runs is unverified on any board. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- MAINTAINERS | 7 ++ drivers/net/mdio/Kconfig | 11 ++ drivers/net/mdio/Makefile | 1 + drivers/net/mdio/mdio-airoha-en8811h.c | 160 +++++++++++++++++++++++++ drivers/net/phy/air_phy_lib.h | 8 +- include/net/phy/air_phy.h | 23 ++++ 6 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 drivers/net/mdio/mdio-airoha-en8811h.c create mode 100644 include/net/phy/air_phy.h diff --git a/MAINTAINERS b/MAINTAINERS index b23fb6f2f4ef..2d2748c44c77 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -750,6 +750,13 @@ S: Supported F: fs/aio.c F: include/linux/*aio*.h =20 +AIROHA EN8811H MCU MDIO DRIVER +M: Aleksei Sviridkin +L: netdev@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/net/airoha,en8811h-mcu.yaml +F: drivers/net/mdio/mdio-airoha-en8811h.c + AIROHA ETHERNET DRIVER M: Lorenzo Bianconi L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig index d44278f26fab..10cea4235b42 100644 --- a/drivers/net/mdio/Kconfig +++ b/drivers/net/mdio/Kconfig @@ -29,6 +29,17 @@ config MDIO_AIROHA This module provides a driver for the MDIO busses found in the Airoha AN7583 SoC's. =20 +config MDIO_AIROHA_EN8811H + tristate "Airoha EN8811H MDIO device support" + depends on OF_MDIO + select AIR_NET_PHYLIB + help + This module provides a driver for the Airoha EN8811H, which is an + MD32 microcontroller until firmware is downloaded into it and only + becomes an Ethernet PHY afterwards. The driver downloads that + firmware once it becomes readable, or adopts firmware a bootloader + left running, before letting the PHY be probed. + config MDIO_SUN4I tristate "Allwinner sun4i MDIO interface support" depends on ARCH_SUNXI || COMPILE_TEST diff --git a/drivers/net/mdio/Makefile b/drivers/net/mdio/Makefile index 048586746026..06d096675dac 100644 --- a/drivers/net/mdio/Makefile +++ b/drivers/net/mdio/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_FWNODE_MDIO) +=3D fwnode_mdio.o obj-$(CONFIG_OF_MDIO) +=3D of_mdio.o =20 obj-$(CONFIG_MDIO_AIROHA) +=3D mdio-airoha.o +obj-$(CONFIG_MDIO_AIROHA_EN8811H) +=3D mdio-airoha-en8811h.o obj-$(CONFIG_MDIO_ASPEED) +=3D mdio-aspeed.o obj-$(CONFIG_MDIO_BCM_IPROC) +=3D mdio-bcm-iproc.o obj-$(CONFIG_MDIO_BCM_UNIMAC) +=3D mdio-bcm-unimac.o diff --git a/drivers/net/mdio/mdio-airoha-en8811h.c b/drivers/net/mdio/mdio= -airoha-en8811h.c new file mode 100644 index 000000000000..595b1b72bc01 --- /dev/null +++ b/drivers/net/mdio/mdio-airoha-en8811h.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Airoha EN8811H MDIO device driver + * + * The EN8811H is an MD32 microcontroller until firmware is downloaded into + * it, and only then an Ethernet PHY. + * + * Copyright (C) 2026 Aleksei Sviridkin + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define EN8811H_FW_POLL_MIN_MS 1000 +#define EN8811H_FW_POLL_MAX_MS 30000 +#define EN8811H_FW_WARN_MS 60000 + +struct en8811h_mcu { + struct mdio_device *mdiodev; + struct gpio_desc *reset_gpio; + struct delayed_work fw_poll; + unsigned int poll_ms; + unsigned int waited_ms; + u32 fw_version; + bool warned; +}; + +static void en8811h_mcu_fw_poll(struct work_struct *work) +{ + struct en8811h_mcu *mcu =3D container_of(to_delayed_work(work), + struct en8811h_mcu, fw_poll); + struct device *dev =3D &mcu->mdiodev->dev; + int ret; + + ret =3D air_en8811h_fw_download(mcu->mdiodev, &mcu->fw_version); + if (ret >=3D 0) { + dev_dbg(dev, "firmware %08x running after %ums\n", + mcu->fw_version, mcu->waited_ms); + return; + } + + mcu->waited_ms +=3D mcu->poll_ms; + if (!mcu->warned && mcu->waited_ms >=3D EN8811H_FW_WARN_MS) { + if (ret =3D=3D -ENOENT) + dev_warn(dev, "still waiting for %s and %s\n", + EN8811H_MD32_DM, EN8811H_MD32_DSP); + else + dev_warn(dev, "firmware download keeps failing: %pe\n", + ERR_PTR(ret)); + mcu->warned =3D true; + } + + mcu->poll_ms =3D min(mcu->poll_ms * 2, EN8811H_FW_POLL_MAX_MS); + queue_delayed_work(system_freezable_wq, &mcu->fw_poll, + msecs_to_jiffies(mcu->poll_ms)); +} + +/* The firmware lives in volatile RAM: no reset while the MD32 reports rea= dy. */ +static void en8811h_mcu_reset_if_dormant(struct en8811h_mcu *mcu) +{ + struct mdio_device *mdiodev =3D mcu->mdiodev; + struct device *dev =3D &mdiodev->dev; + u32 assert_us =3D 0, deassert_us =3D 0; + int ret; + + if (air_en8811h_mcu_running(mdiodev)) { + dev_dbg(dev, "MD32 already running, adopting it\n"); + return; + } + + if (!mcu->reset_gpio) + return; + + device_property_read_u32(dev, "reset-assert-us", &assert_us); + device_property_read_u32(dev, "reset-deassert-us", &deassert_us); + + ret =3D gpiod_direction_output(mcu->reset_gpio, 1); + if (ret) { + dev_warn(dev, "reset not asserted: %pe\n", ERR_PTR(ret)); + return; + } + + if (assert_us) + fsleep(assert_us); + + gpiod_set_value_cansleep(mcu->reset_gpio, 0); + if (deassert_us) + fsleep(deassert_us); +} + +static int en8811h_mcu_probe(struct mdio_device *mdiodev) +{ + struct device *dev =3D &mdiodev->dev; + struct en8811h_mcu *mcu; + + mcu =3D devm_kzalloc(dev, sizeof(*mcu), GFP_KERNEL); + if (!mcu) + return -ENOMEM; + + mcu->mdiodev =3D mdiodev; + mdiodev_set_drvdata(mdiodev, mcu); + + /* The core claims reset-gpios only for devices flagged as PHYs. */ + mcu->reset_gpio =3D devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); + if (IS_ERR(mcu->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(mcu->reset_gpio), + "failed to get reset GPIO\n"); + + if (mcu->reset_gpio) + gpiod_set_consumer_name(mcu->reset_gpio, "EN8811H reset"); + + en8811h_mcu_reset_if_dormant(mcu); + + mcu->poll_ms =3D EN8811H_FW_POLL_MIN_MS; + INIT_DELAYED_WORK(&mcu->fw_poll, en8811h_mcu_fw_poll); + /* Freezable: neither the file lookup nor the download may land on + * a suspending bus. + */ + queue_delayed_work(system_freezable_wq, &mcu->fw_poll, 0); + + return 0; +} + +static void en8811h_mcu_remove(struct mdio_device *mdiodev) +{ + struct en8811h_mcu *mcu =3D mdiodev_get_drvdata(mdiodev); + + cancel_delayed_work_sync(&mcu->fw_poll); +} + +static const struct of_device_id en8811h_mcu_of_match[] =3D { + { .compatible =3D "airoha,en8811h-mcu" }, + { } +}; +MODULE_DEVICE_TABLE(of, en8811h_mcu_of_match); + +static struct mdio_driver en8811h_mcu_driver =3D { + .probe =3D en8811h_mcu_probe, + .remove =3D en8811h_mcu_remove, + .mdiodrv.driver =3D { + .name =3D "airoha-en8811h-mcu", + .of_match_table =3D en8811h_mcu_of_match, + }, +}; + +mdio_module_driver(en8811h_mcu_driver); + +MODULE_FIRMWARE(EN8811H_MD32_DM); +MODULE_FIRMWARE(EN8811H_MD32_DSP); + +MODULE_DESCRIPTION("Airoha EN8811H MDIO device driver"); +MODULE_AUTHOR("Aleksei Sviridkin "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/air_phy_lib.h b/drivers/net/phy/air_phy_lib.h index 6823812c8fd5..a8329223dd4f 100644 --- a/drivers/net/phy/air_phy_lib.h +++ b/drivers/net/phy/air_phy_lib.h @@ -10,6 +10,8 @@ =20 #include =20 +#include + #define AIR_EXT_PAGE_ACCESS 0x1f =20 #define AIR_PHY_PAGE_STANDARD 0x0000 @@ -29,9 +31,6 @@ #define AIR_BPBUS_RD_DATA_HIGH 0x17 #define AIR_BPBUS_RD_DATA_LOW 0x18 =20 -#define EN8811H_MD32_DM "airoha/EthMD32.dm.bin" -#define EN8811H_MD32_DSP "airoha/EthMD32.DSP.bin" - #define AIR_FW_ADDR_DM 0x00000000 #define AIR_FW_ADDR_DSP 0x00100000 =20 @@ -59,9 +58,6 @@ struct firmware; =20 int air_fw_write_buf(struct mdio_device *mdiodev, u32 address, const struct firmware *fw); -bool air_en8811h_mcu_running(struct mdio_device *mdiodev); int air_en8811h_wait_mcu_ready(struct mdio_device *mdiodev); -/* Returns 1 when it adopted firmware that was already running. */ -int air_en8811h_fw_download(struct mdio_device *mdiodev, u32 *fw_version); =20 #endif /* __AIR_PHY_LIB_H */ diff --git a/include/net/phy/air_phy.h b/include/net/phy/air_phy.h new file mode 100644 index 000000000000..03cb3465ef8d --- /dev/null +++ b/include/net/phy/air_phy.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2026 Airoha Technology Corp. + * Copyright (C) 2026 Collabora Ltd. + * Louis-Alexis Eyraud + * Copyright (C) 2026 Aleksei Sviridkin + */ + +#ifndef __NET_PHY_AIR_PHY_H +#define __NET_PHY_AIR_PHY_H + +#include + +struct mdio_device; + +#define EN8811H_MD32_DM "airoha/EthMD32.dm.bin" +#define EN8811H_MD32_DSP "airoha/EthMD32.DSP.bin" + +bool air_en8811h_mcu_running(struct mdio_device *mdiodev); +/* Returns 1 when it adopted firmware that was already running. */ +int air_en8811h_fw_download(struct mdio_device *mdiodev, u32 *fw_version); + +#endif /* __NET_PHY_AIR_PHY_H */ --=20 2.53.0 From nobody Sat Sep 26 03:17:25 2026 Received: from mail-wm1-f48.google.com (mail-wm1-f48.google.com [209.85.128.48]) (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 805A351FCDD for ; Fri, 4 Sep 2026 19:03:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548611; cv=none; b=qD5Gc7baljbxBBwV8QnKRwvcQ5g+kVmm4qFTZNtlOmngq9Oa+2Iucy0mTz+mFsWtcEMfoZepQLzdA+VsqycdKJOUOrbGDFu0WurOyVr3GwebgJ9LC11zMtJPnRAHGSNRrgHKL3xhgKiQGS7QF11sx7WJik/krbfTUS9ppwe1260= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548611; c=relaxed/simple; bh=JBz2NQi/Bv+zFtP/6/uWkbFU+cjjjMSWIux6M1Takzc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Y3MY3sGbwFNOec1hDNovQl0fgYjSDiqfHbV2NbJBKYyPP51gVjxIiZ6MjBZzM8A342EKBm9GyIoZqxYJkNu/0KjuQuFtaebfkWcSx8BOZI5GmRy0P+NyoFbawCyyfDVA0hpE+Fw9nhMcZ9/v9HECqWm3s5VvyEclZopIXKJXCZI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la; spf=pass smtp.mailfrom=lex.la; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b=W8/CKSqg; arc=none smtp.client-ip=209.85.128.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lex.la Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b="W8/CKSqg" Received: by mail-wm1-f48.google.com with SMTP id 5b1f17b1804b1-49b8e527d63so16490175e9.2 for ; Fri, 04 Sep 2026 12:03:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1788548598; x=1789153398; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=0/1c+HSbaGv+gRPu7wfaFP7mAOnMXFXKdtCxWbULAdA=; b=W8/CKSqgE+uTj0HpQPV0h5Ogg737/dlEsYYWy4oZRQXTiPJSW5Fr9Y99c65MvXLUcm Y1SEIToIEQqdUXgqlvjCFApp4tvXRXEdnTdxgoyzh/BbIhU1zMW7FWQGslonu859WFOF CqKcLxL5de6snWk/zYRb+wib4X2kpBn2q+hPACAEH6JMERTMrAUUPhB14u1PTpTQ7HCq ysmF2wDd1OHSNLH79p/X1Pv7n9oqP+eRcsZXeMyom7N7FDn9HDGJ6yqUUnjeO/mpPcCo cWmq4fOKcMaM0ZbmdU5TphCYT2pYphkesieozQGgrCjjjNDDHICN0Js6ZvCFPBm5JmOy Q4BA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788548598; x=1789153398; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=0/1c+HSbaGv+gRPu7wfaFP7mAOnMXFXKdtCxWbULAdA=; b=U3LD3I8+I6FmFifVQNx5p4amj8Xd6JAe6Ix7PiTjaNHS+HL+91FjgceCznGHIsFGpv LTXxNYBJp7ToyMACO3TdFvTQzVuUNsTBV+9KN/T+1rF9FQKhYz4IelnIZDpKt/hSN2uP QNftoQzRjVT8h8kkxT1yQENzrlw2MZcSolnNb792o9qX8TLPhYbvjDweHmYbYgEH/Mw1 vnwzbM9Zldl9/bc18hNQ0Kba7Q3eVSmSWnry9/ZyyiEhkmqz9YTKqhTJ/ddYq8JY9zdz myUXU4xSJaA2hHkKATxGN1yEfQDhYFduJfgl0eU6FNTd0wIn+WOOCXh3Aj9RqNUMS87y OaWA== X-Forwarded-Encrypted: i=1; AKwUvBwWcAKnIocAt53ZGiXENzWVqNyI5XPiZd89BK8EXBsCSiDKnmRZPaor3DBtPdt7dQIEr75LPukfaiYFfGw=@vger.kernel.org X-Gm-Message-State: AFuF++mUvU1brIRIMdgP5bobPrUiViYBULuR68fQToWmtBFfLFQZa5SU MwwHbt2K252E8qpLYJm7r/ETLsULYsOYFDVGOVVvAvSvv4PhhxJ6hRhZAP1oVtNMCVg= X-Gm-Gg: AYBFou2FUACri11C1QGKnVNRjZgLzoXApmLgJ3+cMbCmTiEN8tNdzwm9fK+iSuYnevk iM2FP88+yRtkCc1WW/9N5BjuaMUngbu18W1n6FPQljVkhF6IpkIFXD/ZL8+ZACg8+VCR6/smqmA w7LtY3O9D23o7i1e9t8LeYmxrqAGajg4UCShJBFJTlVuY9eFXWJgnMcx1mKv0Mi7sIDwT89yPW/ 0ilyGQ4dxTxpDL9fR8OwfHli+emzEL1jhz9oIchSCvC9bEIn+ZvKK6L5mP0xmgNllFcdHHZlJLI Msg/3Wr/kU0u/hGOzCGXwMqizhzWvH/b06yGSp20mn43ddLU+6dY+66n3Wq7mmup6e/DdR53PjC mPbWJWqGCIevkIOFnC65Y9g2qzPBF/b8cd+S6jmyFw5AUgQc3Iwyy9GF+IW0KhQw1V6zzDbsEDD +4dxrTqu9OJNSRDSn11TbTIaTLF8qvoLr2dpdCqOE= X-Received: by 2002:a05:600c:1914:b0:49c:ff23:a6d5 with SMTP id 5b1f17b1804b1-49cff23a70bmr35293945e9.0.1788548597648; Fri, 04 Sep 2026 12:03:17 -0700 (PDT) Received: from remote-01 ([84.17.55.227]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49cee60d8a6sm172195485e9.10.2026.09.04.12.03.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2026 12:03:17 -0700 (PDT) From: Aleksei Sviridkin To: Andrew Lunn , Andrew Lunn , Heiner Kallweit , Russell King , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: Eric Woudstra , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH net-next v2 08/10] net: mdio: en8811h: add the nested pass-through bus Date: Fri, 4 Sep 2026 19:03:02 +0000 Message-ID: <9fefcf920098876766f6ce7ce0f6646e89ea3181.1788548229.git.f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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" Registering the bus is what publishes the PHY, so it must happen only once the MD32 is running its firmware. Put the PHY on a bus of its own rather than on the parent so that the device tree can describe it normally, interrupts included, and so that the MCU keeps ownership of the reset line the PHY must not touch. Only the address the MD32 answers on is passed through; every other address returns -ENODEV, so scanning this bus cannot produce anything but this chip's PHY. phy_mask would express the same thing but is not usable here: of_mdiobus_register() overwrites it before walking the children. The parent's interrupt for that address is carried over, since a parent that fills irq[] from its own interrupt domain - a switch, say - would otherwise leave the PHY polling; an interrupts property on the PHY's node still wins. Reach the parent through the mdiobus_*_nested() accessors, which take its lock at MDIO_MUTEX_NESTED, the way the DSA drivers reach through a child bus into their parent. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- drivers/net/mdio/mdio-airoha-en8811h.c | 134 +++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 6 deletions(-) diff --git a/drivers/net/mdio/mdio-airoha-en8811h.c b/drivers/net/mdio/mdio= -airoha-en8811h.c index 595b1b72bc01..222aa4b11b95 100644 --- a/drivers/net/mdio/mdio-airoha-en8811h.c +++ b/drivers/net/mdio/mdio-airoha-en8811h.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include =20 @@ -26,12 +28,104 @@ struct en8811h_mcu { struct mdio_device *mdiodev; struct gpio_desc *reset_gpio; struct delayed_work fw_poll; + struct mii_bus *bus; unsigned int poll_ms; unsigned int waited_ms; u32 fw_version; bool warned; + bool fw_running; }; =20 +static int en8811h_mcu_read(struct mii_bus *bus, int addr, int regnum) +{ + struct en8811h_mcu *mcu =3D bus->priv; + + if (addr !=3D mcu->mdiodev->addr) + return -ENODEV; + + return mdiobus_read_nested(mcu->mdiodev->bus, addr, regnum); +} + +static int en8811h_mcu_write(struct mii_bus *bus, int addr, int regnum, u1= 6 val) +{ + struct en8811h_mcu *mcu =3D bus->priv; + + if (addr !=3D mcu->mdiodev->addr) + return -ENODEV; + + return mdiobus_write_nested(mcu->mdiodev->bus, addr, regnum, val); +} + +static int en8811h_mcu_read_c45(struct mii_bus *bus, int addr, int devad, + int regnum) +{ + struct en8811h_mcu *mcu =3D bus->priv; + + if (addr !=3D mcu->mdiodev->addr) + return -ENODEV; + + return mdiobus_c45_read_nested(mcu->mdiodev->bus, addr, devad, regnum); +} + +static int en8811h_mcu_write_c45(struct mii_bus *bus, int addr, int devad, + int regnum, u16 val) +{ + struct en8811h_mcu *mcu =3D bus->priv; + + if (addr !=3D mcu->mdiodev->addr) + return -ENODEV; + + return mdiobus_c45_write_nested(mcu->mdiodev->bus, addr, devad, regnum, + val); +} + +static int en8811h_mcu_bus_register(struct en8811h_mcu *mcu) +{ + struct device *dev =3D &mcu->mdiodev->dev; + struct mii_bus *parent =3D mcu->mdiodev->bus; + struct device_node *np; + struct mii_bus *bus; + int ret; + + np =3D of_get_child_by_name(dev->of_node, "mdio"); + if (!np) + return -ENODEV; + + /* Not devm: this is retried, and a devm bus would only be freed at + * detach. + */ + bus =3D mdiobus_alloc(); + if (!bus) { + of_node_put(np); + return -ENOMEM; + } + + bus->name =3D "airoha-en8811h"; + snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); + bus->priv =3D mcu; + bus->parent =3D dev; + bus->irq[mcu->mdiodev->addr] =3D parent->irq[mcu->mdiodev->addr]; + + if (parent->read) { + bus->read =3D en8811h_mcu_read; + bus->write =3D en8811h_mcu_write; + } + if (parent->read_c45) { + bus->read_c45 =3D en8811h_mcu_read_c45; + bus->write_c45 =3D en8811h_mcu_write_c45; + } + + ret =3D of_mdiobus_register(bus, np); + of_node_put(np); + if (ret) { + mdiobus_free(bus); + return ret; + } + + mcu->bus =3D bus; + return 0; +} + static void en8811h_mcu_fw_poll(struct work_struct *work) { struct en8811h_mcu *mcu =3D container_of(to_delayed_work(work), @@ -39,21 +133,35 @@ static void en8811h_mcu_fw_poll(struct work_struct *wo= rk) struct device *dev =3D &mcu->mdiodev->dev; int ret; =20 - ret =3D air_en8811h_fw_download(mcu->mdiodev, &mcu->fw_version); - if (ret >=3D 0) { + if (!mcu->fw_running) { + ret =3D air_en8811h_fw_download(mcu->mdiodev, &mcu->fw_version); + if (ret < 0) + goto retry; + dev_dbg(dev, "firmware %08x running after %ums\n", mcu->fw_version, mcu->waited_ms); - return; + /* Registration is a new phase: its own backoff and warning. */ + mcu->fw_running =3D true; + mcu->poll_ms =3D EN8811H_FW_POLL_MIN_MS; + mcu->warned =3D false; } =20 + /* fwnode_mdio defers while the PHY node's interrupt controller is + * missing, so a failure here is not necessarily permanent. + */ + ret =3D en8811h_mcu_bus_register(mcu); + if (!ret) + return; + +retry: mcu->waited_ms +=3D mcu->poll_ms; if (!mcu->warned && mcu->waited_ms >=3D EN8811H_FW_WARN_MS) { - if (ret =3D=3D -ENOENT) + if (!mcu->fw_running && ret =3D=3D -ENOENT) dev_warn(dev, "still waiting for %s and %s\n", EN8811H_MD32_DM, EN8811H_MD32_DSP); else - dev_warn(dev, "firmware download keeps failing: %pe\n", - ERR_PTR(ret)); + dev_warn(dev, "PHY not up after %ums: %pe\n", + mcu->waited_ms, ERR_PTR(ret)); mcu->warned =3D true; } =20 @@ -99,6 +207,7 @@ static int en8811h_mcu_probe(struct mdio_device *mdiodev) { struct device *dev =3D &mdiodev->dev; struct en8811h_mcu *mcu; + struct device_node *np; =20 mcu =3D devm_kzalloc(dev, sizeof(*mcu), GFP_KERNEL); if (!mcu) @@ -107,6 +216,15 @@ static int en8811h_mcu_probe(struct mdio_device *mdiod= ev) mcu->mdiodev =3D mdiodev; mdiodev_set_drvdata(mdiodev, mcu); =20 + /* Registration needs this only once the firmware runs, but a DT + * hole should fail the bind now, not as a work-item error later. + */ + np =3D of_get_child_by_name(dev->of_node, "mdio"); + if (!np) + return dev_err_probe(dev, -ENODEV, + "no mdio node describing the PHY\n"); + of_node_put(np); + /* The core claims reset-gpios only for devices flagged as PHYs. */ mcu->reset_gpio =3D devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); if (IS_ERR(mcu->reset_gpio)) @@ -133,6 +251,10 @@ static void en8811h_mcu_remove(struct mdio_device *mdi= odev) struct en8811h_mcu *mcu =3D mdiodev_get_drvdata(mdiodev); =20 cancel_delayed_work_sync(&mcu->fw_poll); + if (mcu->bus) { + mdiobus_unregister(mcu->bus); + mdiobus_free(mcu->bus); + } } =20 static const struct of_device_id en8811h_mcu_of_match[] =3D { --=20 2.53.0 From nobody Sat Sep 26 03:17:25 2026 Received: from mail-wm1-f45.google.com (mail-wm1-f45.google.com [209.85.128.45]) (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 17ED93F58D6 for ; Fri, 4 Sep 2026 19:03:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548609; cv=none; b=IXlJNj7gIyqQ/TBGnNY6UgYZDOJv0CXlw0Q/Iu9pdYCIRYN4L+PlGoLZ9uM5JTIWtoSL819EYNB+WSlGqm6jbzI9vWIaK/yiDmfEpOwJrgCry92YCJtaqHG540mRCI3ORG8gbT20QygXrf5Of4TFjH8HHIurRR3Sc78Xs9NNtCY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548609; c=relaxed/simple; bh=PO8a5Z8DiIMETb3iouwkHF/HKHTLWWj3iX36fpVEXKY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VqknH7ddjtPgtTe3ukM1dAqMXQU1kYlAnjBk07+RuRbfYlDeRidhruU57FqIP6MH2TS536ZeYqhiz68XLziURvYZg8NJ5+Rl1U/jpCdfmfSIY+OpC7uj523+Vu8IizjP7IVEjkndijcQYEaJ44yD8a3PLGId7JeqJNSskUX5aWs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la; spf=pass smtp.mailfrom=lex.la; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b=UWyq9E2y; arc=none smtp.client-ip=209.85.128.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lex.la Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b="UWyq9E2y" Received: by mail-wm1-f45.google.com with SMTP id 5b1f17b1804b1-4957eefd361so10928885e9.1 for ; Fri, 04 Sep 2026 12:03:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1788548599; x=1789153399; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=ggwy/baXAuOKAxlowPZX6KfzPl9ZtpnT/akRZO0db6E=; b=UWyq9E2yoBfNPQhHbIYgvFzpnj2u9mR4J0oAh8Dgku4SxbeNsP1lcmv8H8uofrImf1 wycGJgZZ1w7J9dbqUWSgOf+T4ZRB7EqOVe2lPssdGTMokd2KCBUtV/kW6Dn5P4pxdZjf jUWankfU2e5ekyqTDod/Ux/NSGLBNxJIXfW2LXt/aInD+DaLycW8ydopSB/EhIx+ARop o9e0jFesU8Cr4Tj6lID2rp1lUkQluIMhX6N79qbhcMwr6cEwmYznFP2wEewEXtsrj0H+ JAO8m0cm+nMvWzm8jIFQECFdicPGN6VyQh11TiK/gN9vPgqF9Mpr+qZewcTP9DkB2esk fC3g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788548599; x=1789153399; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=ggwy/baXAuOKAxlowPZX6KfzPl9ZtpnT/akRZO0db6E=; b=ajv0GzSN4YaX45cqysWvV8hxb1mqKZIivPDqcbiKGoP0+HGeQtJm3SFEV/QwwCzOku 7cJogm7m0pO26KSSeGYqCbynzBYtfIuQGZ2iGPylud9jASYJ6/5394avAbrojyfcHZTO NjzYVDj6gvVlgU2F2FhvE6GmK9Q9s0lyg5dW3mMvwNNvLPeCgols3PJQP+GoXHR8vNul o2RLcpECh2hNFOdwgcfIDpOaz+fYzAnGuLHty/9Boj7AA8X7iEQGG/yq5Sk4QfH9admt Oz3Sx9s1Mv33PfRCgLmwou0EtGRaR/am08n1Ms7TYowa4fze7Ki6zQ4JSPfRr5AvcT++ MeVg== X-Forwarded-Encrypted: i=1; AKwUvBy19XpX2Bk23L+2jooOmAdbzRxWEfS/ykUrvd2eFR+Q7WAr8B5sMHDHisUYbaEcinT5b3IOtIAE+NkNQ7Y=@vger.kernel.org X-Gm-Message-State: AFuF++meG0B3KhzNepWBr8SZxzeykHci3i0YoFCnNK7uTwvzQoc1E3Qd rJXUvbAUzldRFSnDO2V+J5HJafp0Eob7J5dElX2Etuk7PuTByTgc2F2sr9pw07+rbXU= X-Gm-Gg: AYBFou2vKos+CDidwjIeC2pqDgN4Z+Xh8wuIWXiMN+HT2yBQj68Ymhhfh8nni57oM9B 090mm+BKwIZfX1Wlm9PkbByAuFFhF6+4/pr1eBFVj69DMVzQq4PNwKU/pJkeZKymeyOp9QRWUDx liyVilp30e56yq248NXh7Vg1/d3SLajyYXiEtxjdec+6eujMFx9RdBUcdw7+OOYb/5GGBVeNnOm MDIJD4179LjX1gnCkEvQ0KpxJ1gvwEKfQwTmP4/9QXzHebp7X970BYpl8kZSwnWAmAJdOYnVPtF r5kiprVTkSHvVUWInbpsAmvr5f/Ffm9jMqkAvuwP01yXvulvijlaya5I+lVVPhnzXQ7svYlYqq+ mfEbqtZdhG50Q7s6RqZJdO8BK51lLij52lchFckQDYRcKalCFxsV6ySINlX7xMPYR3cQwi+08j9 3gppgA2dmQNYBuJwysMXD9rB0Y2FZaZOQJNc/G+Us= X-Received: by 2002:a05:600c:1991:b0:49b:2796:be30 with SMTP id 5b1f17b1804b1-49cf824f7damr77027875e9.11.1788548599214; Fri, 04 Sep 2026 12:03:19 -0700 (PDT) Received: from remote-01 ([84.17.55.227]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49cee60d8a6sm172195485e9.10.2026.09.04.12.03.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2026 12:03:18 -0700 (PDT) From: Aleksei Sviridkin To: Andrew Lunn , Andrew Lunn , Heiner Kallweit , Russell King , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: Eric Woudstra , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH net-next v2 09/10] net: phylink: wait for PHYs that are known to probe late Date: Fri, 4 Sep 2026 19:03:03 +0000 Message-ID: <3662f8fafff9a386dcf1e798bb85d2d7cede7079.1788548229.git.f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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" A PHY whose driver or firmware lives on a filesystem mounted after the MAC probes cannot be connected when the port is set up, and the port is lost for the rest of the uptime. Let a port declare that with phy-needs-host-firmware and poll for the PHY instead of failing. Return 0 rather than -ENODEV, because DSA reads -ENODEV as permission to look for the PHY on the switch's internal MDIO bus, which is the wrong device. Wait for a driver that has bound rather than a device that exists, because the generic driver would otherwise bind and cannot drive such a PHY. Deferring the MAC's own probe is not an option: it would take every port with it, including the one needed to mount the filesystem that holds the firmware. Keep polling after a failed connect, because a failed bringup detaches the PHY and whether the next attempt succeeds depends on which driver binds it, which phylink cannot see; -EBUSY is the exception and stops the poller, because it means the PHY is already attached, here or elsewhere, and polling cannot change that, after which the port keeps the pending state and reports no link modes until it is reconnected. When the port is running and nothing else is holding the link down, the MAC is configured before the PHY is started, the order phylink_start() uses, and the only other place that starts a late PHY should not use a different one; that also makes the forced configuration run at a deterministic moment rather than whenever the workqueue reaches it. rtnl is taken with trylock so the poller never blocks on it, which keeps it from parking a shared workqueue worker while another thread holds rtnl. The asynchronous cancel in phylink_disconnect_phy() is then enough, because the stop flag makes a run that slips through a no-op. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- drivers/net/phy/phylink.c | 179 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 172 insertions(+), 7 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 97712c1572ad..bceeac954779 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -73,6 +73,15 @@ struct phylink { struct phylink_link_state phy_state; unsigned int phy_ib_mode; struct work_struct resolve; + /* Set before the poller is queued, cleared under rtnl. */ + struct fwnode_handle *slow_phy_fwnode; + u32 slow_phy_flags; + struct delayed_work slow_phy_poll; + unsigned int slow_phy_poll_ms; + unsigned int slow_phy_waited_ms; + bool slow_phy_err_logged; + /* Read unlocked by the poller; a stale read costs one poll cycle. */ + bool slow_phy_stop; unsigned int pcs_neg_mode; unsigned int pcs_state; =20 @@ -1829,6 +1838,8 @@ int phylink_set_fixed_link(struct phylink *pl, } EXPORT_SYMBOL_GPL(phylink_set_fixed_link); =20 +static void phylink_slow_phy_poll(struct work_struct *work); + /** * phylink_create() - create a phylink instance * @config: a pointer to the target &struct phylink_config @@ -1867,6 +1878,7 @@ struct phylink *phylink_create(struct phylink_config = *config, mutex_init(&pl->phydev_mutex); mutex_init(&pl->state_mutex); INIT_WORK(&pl->resolve, phylink_resolve); + INIT_DELAYED_WORK(&pl->slow_phy_poll, phylink_slow_phy_poll); =20 pl->config =3D config; if (config->type =3D=3D PHYLINK_NETDEV) { @@ -1950,6 +1962,10 @@ void phylink_destroy(struct phylink *pl) if (pl->link_gpio) gpiod_put(pl->link_gpio); =20 + WRITE_ONCE(pl->slow_phy_stop, true); + cancel_delayed_work_sync(&pl->slow_phy_poll); + fwnode_handle_put(pl->slow_phy_fwnode); + cancel_work_sync(&pl->resolve); kfree(pl); } @@ -2219,10 +2235,8 @@ static int phylink_bringup_phy(struct phylink *pl, s= truct phy_device *phy, } =20 static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy, - phy_interface_t interface) + phy_interface_t interface, u32 flags) { - u32 flags =3D 0; - if (WARN_ON(pl->cfg_link_an_mode =3D=3D MLO_AN_FIXED)) return -EINVAL; =20 @@ -2260,7 +2274,7 @@ int phylink_connect_phy(struct phylink *pl, struct ph= y_device *phy) pl->link_config.interface =3D pl->link_interface; } =20 - ret =3D phylink_attach_phy(pl, phy, pl->link_interface); + ret =3D phylink_attach_phy(pl, phy, pl->link_interface, 0); if (ret < 0) return ret; =20 @@ -2272,6 +2286,124 @@ int phylink_connect_phy(struct phylink *pl, struct = phy_device *phy) } EXPORT_SYMBOL_GPL(phylink_connect_phy); =20 +#define PHYLINK_SLOW_PHY_POLL_MS 1000 +#define PHYLINK_SLOW_PHY_WARN_MS 60000 +#define PHYLINK_SLOW_PHY_POLL_MAX_MS 30000 + +/* Bound, not drv: drv is published before the driver's probe runs. The + * device lock cannot be taken under rtnl, and losing this race costs a + * generic-driver attach, not memory safety. + */ +static bool phylink_phy_is_usable(struct phy_device *phy_dev) +{ + return phy_dev && device_is_bound(&phy_dev->mdio.dev); +} + +static void phylink_slow_phy_backoff(struct phylink *pl) +{ + WRITE_ONCE(pl->slow_phy_poll_ms, + min_t(unsigned int, pl->slow_phy_poll_ms * 2, + PHYLINK_SLOW_PHY_POLL_MAX_MS)); +} + +static void phylink_slow_phy_poll(struct work_struct *work) +{ + struct phylink *pl =3D container_of(to_delayed_work(work), struct phylink, + slow_phy_poll); + struct phy_device *phy_dev; + int ret; + + if (READ_ONCE(pl->slow_phy_stop)) + return; + + /* Never block on rtnl: this runs on a shared workqueue. */ + if (!rtnl_trylock()) + goto requeue; + + if (READ_ONCE(pl->slow_phy_stop)) { + rtnl_unlock(); + return; + } + + /* Under rtnl: phylink_disconnect_phy() puts and clears the node. */ + phy_dev =3D fwnode_phy_find_device(pl->slow_phy_fwnode); + if (!phylink_phy_is_usable(phy_dev)) { + if (phy_dev) + phy_device_free(phy_dev); + + pl->slow_phy_waited_ms +=3D pl->slow_phy_poll_ms; + if (pl->slow_phy_waited_ms >=3D PHYLINK_SLOW_PHY_WARN_MS && + pl->slow_phy_waited_ms - pl->slow_phy_poll_ms < + PHYLINK_SLOW_PHY_WARN_MS) + phylink_warn(pl, + "still waiting for %pfw (phy-needs-host-firmware)\n", + pl->slow_phy_fwnode); + /* Past the warn it may never come: stop paying 1 Hz for it. */ + if (pl->slow_phy_waited_ms >=3D PHYLINK_SLOW_PHY_WARN_MS) + phylink_slow_phy_backoff(pl); + rtnl_unlock(); + goto requeue; + } + + if (pl->link_interface =3D=3D PHY_INTERFACE_MODE_NA) { + mutex_lock(&pl->state_mutex); + pl->link_interface =3D phy_dev->interface; + pl->link_config.interface =3D pl->link_interface; + mutex_unlock(&pl->state_mutex); + } + + ret =3D phylink_attach_phy(pl, phy_dev, pl->link_interface, + pl->slow_phy_flags); + phy_device_free(phy_dev); + if (!ret) { + ret =3D phylink_bringup_phy(pl, phy_dev, + pl->link_config.interface); + if (ret) { + phy_detach(phy_dev); + } else { + /* Only a major config programs the masks bringup just + * narrowed; the resolve's own trigger cannot see it. + */ + mutex_lock(&pl->state_mutex); + pl->force_major_config =3D true; + mutex_unlock(&pl->state_mutex); + if (!test_bit(PHYLINK_DISABLE_STOPPED, + &pl->phylink_disable_state)) { + /* MAC first, then the PHY, as phylink_start() + * does; the config is skipped while the + * resolve is disabled. + */ + phylink_run_resolve(pl); + flush_work(&pl->resolve); + phy_start(phy_dev); + } + } + } + if (ret) { + /* The errno does not distinguish permanent from transient. */ + if (!pl->slow_phy_err_logged) { + pl->slow_phy_err_logged =3D true; + phylink_err(pl, "failed to connect late PHY: %pe\n", + ERR_PTR(ret)); + } + + if (ret =3D=3D -EBUSY) { + rtnl_unlock(); + return; + } + phylink_slow_phy_backoff(pl); + } + rtnl_unlock(); + + if (!ret) + return; + +requeue: + queue_delayed_work(system_freezable_power_efficient_wq, + &pl->slow_phy_poll, + msecs_to_jiffies(READ_ONCE(pl->slow_phy_poll_ms))); +} + /** * phylink_of_phy_connect() - connect the PHY specified in the DT mode. * @pl: a pointer to a &struct phylink returned from phylink_create() @@ -2282,7 +2414,8 @@ EXPORT_SYMBOL_GPL(phylink_connect_phy); * specified by @pl. Actions specified in phylink_connect_phy() will be * performed. * - * Returns 0 on success or a negative errno. + * Returns what phylink_fwnode_phy_connect() returns, including 0 for a + * deferred connect with no PHY attached yet. */ int phylink_of_phy_connect(struct phylink *pl, struct device_node *dn, u32 flags) @@ -2300,7 +2433,13 @@ EXPORT_SYMBOL_GPL(phylink_of_phy_connect); * Connect the phy specified @fwnode to the phylink instance specified * by @pl. * - * Returns 0 on success or a negative errno. + * If the port node carries the phy-needs-host-firmware property and the + * PHY is not usable yet, 0 is returned with no PHY connected: a poller + * connects it once its driver has probed. Until then the MAC runs + * without a PHY and ethtool reports no link modes. + * + * Returns 0 on success - the PHY connected, or the deferred connect + * armed - or a negative errno. */ int phylink_fwnode_phy_connect(struct phylink *pl, const struct fwnode_handle *fwnode, @@ -2322,6 +2461,25 @@ int phylink_fwnode_phy_connect(struct phylink *pl, } =20 phy_dev =3D fwnode_phy_find_device(phy_fwnode); + if (fwnode_property_present(fwnode, "phy-needs-host-firmware") && + !phylink_phy_is_usable(phy_dev)) { + /* -ENODEV here would also send DSA to the switch's own bus. */ + if (phy_dev) + phy_device_free(phy_dev); + + fwnode_handle_put(pl->slow_phy_fwnode); + pl->slow_phy_fwnode =3D phy_fwnode; + pl->slow_phy_flags =3D flags; + WRITE_ONCE(pl->slow_phy_poll_ms, PHYLINK_SLOW_PHY_POLL_MS); + pl->slow_phy_waited_ms =3D 0; + pl->slow_phy_err_logged =3D false; + WRITE_ONCE(pl->slow_phy_stop, false); + /* mod_delayed_work: a cancelled poll may still be pending. */ + mod_delayed_work(system_freezable_power_efficient_wq, + &pl->slow_phy_poll, 0); + return 0; + } + /* We're done with the phy_node handle */ fwnode_handle_put(phy_fwnode); if (!phy_dev) @@ -2363,6 +2521,13 @@ void phylink_disconnect_phy(struct phylink *pl) =20 ASSERT_RTNL(); =20 + /* Async is enough: the stop flag no-ops a run that slips through. */ + WRITE_ONCE(pl->slow_phy_stop, true); + cancel_delayed_work(&pl->slow_phy_poll); + /* The next connect re-arms from its own lookup. */ + fwnode_handle_put(pl->slow_phy_fwnode); + pl->slow_phy_fwnode =3D NULL; + mutex_lock(&pl->phydev_mutex); phy =3D pl->phydev; if (phy) @@ -3741,7 +3906,7 @@ static int phylink_sfp_config_phy(struct phylink *pl,= struct phy_device *phy) /* Attach the PHY so that the PHY is present when we do the major * configuration step. */ - ret =3D phylink_attach_phy(pl, phy, config.interface); + ret =3D phylink_attach_phy(pl, phy, config.interface, 0); if (ret < 0) return ret; =20 --=20 2.53.0 From nobody Sat Sep 26 03:17:25 2026 Received: from mail-wm1-f45.google.com (mail-wm1-f45.google.com [209.85.128.45]) (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 156535221F0 for ; Fri, 4 Sep 2026 19:03:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548614; cv=none; b=CJ1pACCW38UVfZEC40e3rstia5zNgHI5gBjeWdUpSQShflItaVo3vqnKlZfU/fPqMJbf+1XEz20kgZGuOH1ZAN5GCzLInXF+kUbNOjCSZA0pc0zoBFKVf6Mbhmq8jGE4Y22FQGYseiwjVH5Z/lS6mZ3lOWtOn/5lMPxFyu/Son8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788548614; c=relaxed/simple; bh=yfXfFA1c3vQG1+Ye7UxWHbvarQ+1G95ouDiPWPxXcDY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VLiOTvWpyPzO4vdMtmVFEtX5oM5StAWRDpGxrA++lYSDFkRGpdmUlcP6waDUsB+2ekMn2kv6RGmNn9M9pcHjmrcRtUaaH+kgz9NB9TFgVM3/qrWWEkGQ+U/JXBw8vGsfweTGkSh7K5KuXaS8h0edowwvpOKQ3o9yy4DgYN1olSQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la; spf=pass smtp.mailfrom=lex.la; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b=REvQzaHS; arc=none smtp.client-ip=209.85.128.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=lex.la Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lex.la Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=lex.la header.i=@lex.la header.b="REvQzaHS" Received: by mail-wm1-f45.google.com with SMTP id 5b1f17b1804b1-499ac87c92bso15409775e9.1 for ; Fri, 04 Sep 2026 12:03:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1788548601; x=1789153401; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=CMh5lYeH3aGg59+QPJC3P1Oz0qgidcMVPi+b3gENV5I=; b=REvQzaHSJtV3hEBDt0Zye8R4e1GhaX3CB5shzqz/lZhvQXG+J4PxnVyoKbZFmAD64k NZ40P2MeQLhrnOdpPvM2Ym/lb0LLFBbQNAJmLZ4kg/npdsWD0sIAiwyxOq6dAfupXGlb vESAxdyUmmNHCKeVCp566frDoJld/t+TgG3+W55VlmdZmEMkPhQo5pbHI34o+fKvZldi kl0WeSs8T/R5pselR0H2HYy6bFcWWAKQvuck5i0jioLJmzwMgNHH/dwguhRrnOwM4Cvc lc+oc0fxf5nkBYEildoOGcx7bKXwSNU7m0psAOlZF/Tk2+1k/rNWEyOIMbpD/WD9xMa6 E3sw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788548601; x=1789153401; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=CMh5lYeH3aGg59+QPJC3P1Oz0qgidcMVPi+b3gENV5I=; b=ZTC7HLj3GDuDxzk4XRzpYpPUYHPnOuaxfEuOgzjEmi7BmvMrKGqqUl+VpQ3R0TDgw7 yhL1A4lVbn7YYvgIp7d/aE1/fQKY4gDq30n2vExEySM6m5eSpBT7IJMlAHTBL6ZPUkXj WuzN0D/SYvN7acW1fO1sgD9ko1TDnQZbr0gZGuQLkrWyifgbz2R7sSBI0ANZVy6pR6xB bMLci4qQ+qEymKaO9ZSw5Q/3ZRf6mJCUmb/FouvVKxd/7iBrP9bZ+WJ+qT/82dlCJ4tq 0hKI9mMucqG4LOL756KR/UYgUmjfhrdKltFCLjdqlJFnS7IGR3/zxGOJazc/MyCEcvWy unsA== X-Forwarded-Encrypted: i=1; AKwUvBwaeMnWJoE3gxUT5MymupsOCi4DQLaTKtu2hCZ82GuXNpaRMNcBMFXJYyP2dzszQDJkmbyf80VgBRTGm94=@vger.kernel.org X-Gm-Message-State: AFuF++n5jdGRCkba0vr5ny7gw1y1sDlB8e090nYQCKbo/Jrk8cMlqbcX BCgJTzblXJpM0yVwUC1ZVhZHjLOwF7hfkkGtpZ/S7B/DQsILP49LCx4M8id94v6W8Rs= X-Gm-Gg: AYBFou0fpIKLULj02AYqt52w1dEqQAnFARVuiYUZB7VfWfOsSsSuaAmYrCE4Fd9RJKD QjF62uVDMQa5AHLm0lhEvoPWXlr6seNpcbCg0EWr/RxYOwdjb6MDwu2A9nWOBzgszCW0bYJLi2b sP3q2kcpr1UNCDPYrGF3as8+7WGBNurEPPsnQWZ0LWAJZlzreyeXyRpv7MlR//rX9xWHb+/MhVd LgxzLyzJzNdNEMYKJkBt5dsqJziznXj+Wv2kUG0gmbmMzpN3jpHNPjeb+crFhv6Lj/J0IaKS3kD moDRfVkxjk8CDZcKlgUy/M/w42gLn6s0rduVTTmN0j8tTI6gDP889w845sGzo/R8lL92ZnaOnA7 X+wAZ3vTWw5c7beMIFM7iVLI68Lzrib50nIsb9OfK+Lzb2fh44/9f++zPT1HMuZ/2eVlGlYw5gm CXO1RN+dKmoHsNeeXY26Kkrzpm6TnVi+sZ8ZWiUDg= X-Received: by 2002:a05:600c:4e11:b0:49c:f2f4:eddd with SMTP id 5b1f17b1804b1-49cf8268795mr95772385e9.16.1788548600659; Fri, 04 Sep 2026 12:03:20 -0700 (PDT) Received: from remote-01 ([84.17.55.227]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49cee60d8a6sm172195485e9.10.2026.09.04.12.03.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2026 12:03:20 -0700 (PDT) From: Aleksei Sviridkin To: Andrew Lunn , Andrew Lunn , Heiner Kallweit , Russell King , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: Eric Woudstra , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH net-next v2 10/10] net: phylink: report no link modes while a late PHY is missing Date: Fri, 4 Sep 2026 19:03:04 +0000 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: 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" A port waiting for its PHY reported the MAC's full set of link modes and accepted settings for them, which describes a link that cannot come up. Report an empty set and refuse to configure until the PHY arrives. Every path through net/ethtool/ zeroes the reply before the get op, so the pending path only stamps the unknown speed and duplex. Setting pause parameters needs the same guard, because it is gated on the same MAC-derived mask; reading them does not, since it reports the configured request rather than a capability. The EEE calls need no guard either: they already return -EOPNOTSUPP when no PHY is attached. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- drivers/net/phy/phylink.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index bceeac954779..942d5fe943a1 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -2290,6 +2290,11 @@ EXPORT_SYMBOL_GPL(phylink_connect_phy); #define PHYLINK_SLOW_PHY_WARN_MS 60000 #define PHYLINK_SLOW_PHY_POLL_MAX_MS 30000 =20 +static bool phylink_slow_phy_pending(struct phylink *pl) +{ + return pl->slow_phy_fwnode && !pl->phydev; +} + /* Bound, not drv: drv is published before the driver's probe runs. The * device lock cannot be taken under rtnl, and losing this race costs a * generic-driver attach, not memory safety. @@ -3087,6 +3092,14 @@ int phylink_ethtool_ksettings_get(struct phylink *pl, =20 ASSERT_RTNL(); =20 + /* No PHY yet: the port supports nothing, not what the MAC alone can. */ + if (phylink_slow_phy_pending(pl)) { + kset->base.port =3D pl->link_port; + kset->base.speed =3D SPEED_UNKNOWN; + kset->base.duplex =3D DUPLEX_UNKNOWN; + return 0; + } + if (pl->phydev) phy_ethtool_ksettings_get(pl->phydev, kset); else @@ -3159,6 +3172,10 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, =20 ASSERT_RTNL(); =20 + /* Would configure the MAC alone, for a link that cannot come up. */ + if (phylink_slow_phy_pending(pl)) + return -EOPNOTSUPP; + if (pl->phydev) { struct ethtool_link_ksettings phy_kset =3D *kset; =20 @@ -3373,6 +3390,10 @@ int phylink_ethtool_set_pauseparam(struct phylink *p= l, if (pl->req_link_an_mode =3D=3D MLO_AN_FIXED) return -EOPNOTSUPP; =20 + /* pl->supported still describes the MAC, so the test below passes. */ + if (phylink_slow_phy_pending(pl)) + return -EOPNOTSUPP; + if (!phylink_test(pl->supported, Pause) && !phylink_test(pl->supported, Asym_Pause)) return -EOPNOTSUPP; --=20 2.53.0