From nobody Sat Sep 26 22:00:14 2026 Received: from mail-ej1-f41.google.com (mail-ej1-f41.google.com [209.85.218.41]) (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 8989627466A for ; Sat, 29 Aug 2026 05:25:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981160; cv=none; b=MAr6Pk2mADfDowsKFOLka7aqYD0ipTJJKSStmqiPRbma4d+kqM/5+QRx6xLy4LFzoj95l7lh8h0Li2VO6iC5g12CvSqZeqg6tR9QA7eINfQGhvwUikRdUMkqNVyw2Di6VRkciqSNjcQIU86KXnpK8CIerWz4bLh13bN65Ic7K3g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981160; c=relaxed/simple; bh=6smDZg6FX3ydlxDcUe1XoFlk/nAtSbiRQRH7DWbaBw0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=t5+J6FwQKf1ZGB3XGVJPCtm42kDdiqx+LBug7TL2v2TaHTqfAYTzq9bGcY4QIeMgJJyPUOZJB6a0vtlnrfo0isB8HVJjWj4tTImGlG7y7x4DWo/to3zRPLIm1H+5PoGzzbmPSVdXwbNC+jRkOQGSXWwjXX/sVYMB1KgAGcWLW28= 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=ehErYBPh; arc=none smtp.client-ip=209.85.218.41 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="ehErYBPh" Received: by mail-ej1-f41.google.com with SMTP id a640c23a62f3a-c25099bb1fbso232147866b.3 for ; Fri, 28 Aug 2026 22:25:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1787981155; x=1788585955; 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=G3HUI19LAi4NPu5wR+/Bmyr8Ia2vgCBzo9Z3ziBwtkg=; b=ehErYBPh/TNr/8vuROvsNKoZWiO8vlljLdNuSW/jHczAgqsKWlAr7K5DvV22orT/nY 74kri//oT3NRijcDqmvxDIezOcxmLYmg8xWP9I1EUcjmQ3VXGb2qqWXyL1VHtxR0EPkG g0NiOhbUTV2mmgx451GVmVFcmjuThKHsbwOP7a4PcoXVAeeLlFoAksifx7NiNrglS9Vz 5UJ5q65Em2Hqb3rTNPMyLqyCW9IuOpAnDzMXWvp6gnUE451zjMw4ic24CJYkwF5WgE3n Rg8OuPrrK2IlAZfUo/+V9LWcq5k621QscWMsQZp2T1EzJnmHo1+SeQ57/u8eTwkTHMn/ nZgA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787981155; x=1788585955; 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=G3HUI19LAi4NPu5wR+/Bmyr8Ia2vgCBzo9Z3ziBwtkg=; b=QF5CN86omAd2GRNd8Nt2yBj1fKv3t2lRZTbR/Vkd/XuruLJqQMr8hLagAqYlJvMuD7 6GKTu7Y0DrU3cfLjN3u0HRZAwrOPrvSRqIYPG1xeKmnXR2oqCFw+nTM4ZiKnFxJ4sLhc XwqwVXb6y8xZ6TQ455lnPVr7/Bi3ydwwYsc7QRnTZ1gwCpO7Hfa04xGisjn+Qbi/epFg Rb7Uhqb9ZZIXN5glPHnDfVd3wxrPC2w0X4UjOSOg1RQmUHLFfVz/QZCcFe2bowJMV2Px JnZjXBIp1WqhLFiY2T3XsTWg8RsdZxuJWttCuSVTyFoQTPCr4A2uEj/CbvPHmurzpwZk DA6w== X-Forwarded-Encrypted: i=1; AHgh+RpPTWz+0EU1tRE9LxAoKKphZ79OW39BfY/oRxwKRag9rE+euxUj5crDkJFDzExp/RNALd8sAjVhE6ZlWoE=@vger.kernel.org X-Gm-Message-State: AFuF++mb1VrVRTa86UJtUab+XkzyHMVHwXTPAhUhqwENMiolsKGjWLnm Yx5I27k16cMVKdTbcwvAJ76+az+6VIDjEJfJ9Qid/Ktcw76sPq+ZuZEszD2nvOkfyAg= X-Gm-Gg: AYBFou1V3tElqaNYHp+FyZ7rJGysT9V1sE40GBmyJ88sHW8eAs9+m1N8mGZJDmEIfPX twNa4u5VP1pNzS4JRyCDXlSzmmVEf3/RPgZmrfp3RthwWe7350gYAkr+VJwqlzMa/jdIHx4PgDi KEjHKBiPpj8yVlAI+DvJHBCF0OuB6nJIYEzRz+/fArh5FyvsMLIfTXUr/17UHqqC05oQba9U/ei QNAgI7lTty5i5+5DwPprn8BPGgkBV+Puw4Rm5emSwBIGE59rkIEW4bippCUkCpl8ghafR1M2qth d/V+2r55cN2lRlt2IOG/i4PFgbbRs4hvmLh5t+luUxY05PzJ9qit2znnSJaIJhr3tHMY/1hqWy+ zUzsh9tbIq4xZxHggnf/WKAA5zpxfPFlk67rsUerDg+7YFgDl4znep5eoQYiG0IuCvxZPgARDAQ 4MrVZtIofeRAwuJJYtR74eoWhA2h9e80aEzTQDK01ygA== X-Received: by 2002:a17:906:c145:b0:c24:bf0b:6b62 with SMTP id a640c23a62f3a-c2556baeae6mr819278466b.4.1787981155025; Fri, 28 Aug 2026 22:25:55 -0700 (PDT) Received: from remote-01 ([45.85.105.214]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c255ee75a36sm163750666b.28.2026.08.28.22.25.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2026 22:25:54 -0700 (PDT) From: Aleksei Sviridkin To: netdev@vger.kernel.org Cc: andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Aleksei Sviridkin Subject: [RFC PATCH net-next 1/9] dt-bindings: net: add Airoha EN8811H PHY MCU Date: Sat, 29 Aug 2026 05:25:38 +0000 Message-ID: <20260829052546.1152446-2-f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260829052546.1152446-1-f@lex.la> References: <20260829052546.1152446-1-f@lex.la> 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 | 83 +++++++++++++++++++ 1 file changed, 83 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..b51a14a3b7b5 --- /dev/null +++ b/Documentation/devicetree/bindings/net/airoha,en8811h-mcu.yaml @@ -0,0 +1,83 @@ +# 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 driven by an MD32 MCU that executes + firmware loaded over MDIO into volatile RAM. Until that firmware runs, + the chip answers its PHY ID but cannot bring up a link, and the + firmware files may live on a filesystem that is not yet mounted when + the MDIO bus is scanned. + + This node describes the MCU as an MDIO device in its own right. The + driver downloads the firmware once the files become available (or + detects firmware already left running by the bootloader) and only + then registers the child MDIO bus, so the PHY node below never + becomes visible before the chip is able to serve it. + + The reset line is owned by this node rather than by the PHY node: + the MD32 keeps its firmware only in volatile RAM, so the reset may + be asserted only while the MCU is not executing firmware. A PHY-node + reset would be pulsed by phy_detach() on every unbind and wipe the + running firmware. + +properties: + compatible: + const: airoha,en8811h-mcu + + reg: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + reset-assert-us: true + + reset-deassert-us: true + + mdio: + $ref: mdio.yaml# + unevaluatedProperties: false + description: + The child bus holding the PHY itself, at the same address the + chip answers on the parent bus. + +required: + - compatible + - reg + - mdio + +additionalProperties: false + +examples: + - | + 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 1>; + 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 8>; + }; + }; + }; + }; --=20 2.53.0 From nobody Sat Sep 26 22:00:14 2026 Received: from mail-ej1-f43.google.com (mail-ej1-f43.google.com [209.85.218.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 F2521354AE3 for ; Sat, 29 Aug 2026 05:25:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981163; cv=none; b=QO7ZcOsjqjj/y9ESlwDvg2Pc9l5YhpNbyZvN6LdRcM9q1p8Y/RxT0YH1GWKoHsCTgh3nzfb1B3kiYVAxh0ZDv/xfZytAHTmgPiHlid0PxfDhWaIHSjs4fY0Z+5eSPBKu5+1vODvo4rL2PBGGVmSftoWC48IPvJQQ+PQ+W5dVKW8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981163; c=relaxed/simple; bh=tKa5j9i3U2hEA89fukkKnmWOEyATOeYt7RNjiBnkF8g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LDfc/ZDLbBJRDNBTebq6+Ygori8LdXPeOyuVCJxJLJ2en7nhzQGDwomrP41I9Xos6/YWWfeTaZ/onP7wZKNrYWYNpwsHLcJZktctXY+3c6Y8gMkkq7opxN9KkS6W+4DEQGVkzdCR/0t5BkC/7FzmwQs3mdoluCOxJrHDZBcniUY= 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=TTNtrB52; arc=none smtp.client-ip=209.85.218.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="TTNtrB52" Received: by mail-ej1-f43.google.com with SMTP id a640c23a62f3a-c1600d040e4so273478366b.1 for ; Fri, 28 Aug 2026 22:25:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1787981157; x=1788585957; 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=6tbb1GitXTJrwSUFBP7Nmbmt66qKmDt6rqJljhVwKiU=; b=TTNtrB52lTweJtY0q4agXLa61PNApfdVadtD44EgkDczUakEXFtyNDxbHSFlSuJCrJ 7N5R7olAB5CrVQa0pp1g7fvKTbGoahgvLFB8csMZ+den9ut5rreKVcAnvh5DJylWfaQp RDSP+5e5Qfl8+U0d79lHFUyqqVepVICaA5jHr48wt3Nfg/XhHC03roCaAmV8MNkns+7U jdY86BNc6xrbLcQ/Ojh1ydd3BAy9WRGd58/sVRlm2FuJq8LR13mHdpoceWjtF6/ayMNn 5ePELdUBSwtk5UJfcSSW+KpzrJrdRBPMgb3NrUQ8MwJMKkRH7HfinjuoAakNx2Xs6EJl /V1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787981157; x=1788585957; 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=6tbb1GitXTJrwSUFBP7Nmbmt66qKmDt6rqJljhVwKiU=; b=Yuz5BchaAqJRdhCO93QOqG7cRErTJZaRopZA1sfLQfgek3RqqUdhGtcgDAq1Mn68ac z1/11+7RzYX3TKqiaywsW6qazPE8p0sqgn47bZf5XW6+uYR/215fJ16rUsnBnEGHhAu6 1iQwME8wbqXHoedIe4Ooxb3VuxNW9xgyssnMYBdzCNDyOdNRh6ziGJa/Wr8VOt9xkfQf /syWnib86FdKj9AK65GsQJNc7HcU8I3hXujIrt5FxUP2sEi2Qjm7g0Iq540zbJn4Y943 RjzyOKGNCO3peKcWI4UXMCUNxXO5qAdETxeJe9KOjURId7hyWyOfYA7C8OuUw/ZESkKg bTFA== X-Forwarded-Encrypted: i=1; AHgh+Ro0kHaX6ulEnaeUPECsbUm9VHxxqp0gr7xPaio73KgcAdLZw5aQQ1uFMjfNbc7YZUGEUzndaCHFfpJ27HI=@vger.kernel.org X-Gm-Message-State: AFuF++nmCcLxsq8qdD+zIKKcMsT5WuImmORBSjJl/VHDBAERcUbnoETS h5KJfpAARb2JiwNLGTQfAz/8fICBZCHTORZ6qfIYyIE0iqafBtx03KYQHijRrrWGdiM= X-Gm-Gg: AYBFou3tQD75psQYJkSrtW10iFRp2nhv2dORHXiog1N4ForcJm9YkUccgp0n7F/VF6M 3Wq1zuYvF0oFxUM2nNNoSsxDFSa9Me3CY0KmT54IYL4noZLqe25Q3e0LNHgtZ4buZISstJY95D7 f71RhD8PiVp5OsH3gECmPeii7aR/Bg/RWx4e1sScyyFMYOb9jzcHA6V31T8tQl0w8pJj8sr5ceS Ft0QsM0LdqKUscJuR/EhPznfT8Sj8PKqPaKMtEd3sb0o5FpPbfm5Y3e81puGv19WsykC3rffWzM F58jDX6MOMftsTD6QeflAXoKSKne2WqyZgG1oh6p5+AkN9yOPBVGsdw0Ilr5U2oxfZBNDWhRp2D DFQv6cMSMyvdZbxpARYuuL0TEQSGEzbgWjQ7Ffr0A/mP6oItxv28g8Fc7sO79m+3k2EjXPU7iZS qfIOP3tsDa4PmboqwXRNyy4kW7YNq9MOpPtxzrYXwKS8jvdOpBpbh4BQ== X-Received: by 2002:a17:907:1b0a:b0:c24:6382:2648 with SMTP id a640c23a62f3a-c256dbefa05mr322975866b.5.1787981157019; Fri, 28 Aug 2026 22:25:57 -0700 (PDT) Received: from remote-01 ([45.85.105.214]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c255ee75a36sm163750666b.28.2026.08.28.22.25.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2026 22:25:56 -0700 (PDT) From: Aleksei Sviridkin To: netdev@vger.kernel.org Cc: andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Aleksei Sviridkin Subject: [RFC PATCH net-next 2/9] dt-bindings: net: ethernet-controller: add slow-to-probe Date: Sat, 29 Aug 2026 05:25:39 +0000 Message-ID: <20260829052546.1152446-3-f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260829052546.1152446-1-f@lex.la> References: <20260829052546.1152446-1-f@lex.la> 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 whose driver is not usable at connect time because the PHY's firmware, or the module carrying its driver, lives in a filesystem that is not mounted yet when the controller probes. Today such a port is dropped at setup and stays unusable for the whole uptime even though the PHY becomes fully functional seconds later. Add a boolean the port node can carry to declare this expected: the connect keeps the port and attaches the PHY once it becomes usable instead of failing. The name and the schema home are an open question of this series: the property is generic and read from the MAC/port node, so it lands here rather than in a vendor binding, but a better-scoped name may exist. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- .../devicetree/bindings/net/ethernet-controller.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/net/ethernet-controller.yaml= b/Documentation/devicetree/bindings/net/ethernet-controller.yaml index 1bafd687dcb1..ca82672b6cb3 100644 --- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml +++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml @@ -113,6 +113,15 @@ properties: description: Specifies a reference to a node representing an IEEE 1588 PTP device. =20 + slow-to-probe: + $ref: /schemas/types.yaml#/definitions/flag + description: + The PHY referenced by phy-handle may not exist, or may not have a + usable driver, when this controller connects to it, because the + driver or firmware arrives later (for example from a filesystem + mounted after the controller probed). Instead of failing, keep + the port and connect the PHY once it becomes usable. + rx-fifo-depth: $ref: /schemas/types.yaml#/definitions/uint32 description: --=20 2.53.0 From nobody Sat Sep 26 22:00:14 2026 Received: from mail-ej1-f45.google.com (mail-ej1-f45.google.com [209.85.218.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 F0511348C52 for ; Sat, 29 Aug 2026 05:26:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981163; cv=none; b=OpKVPK0bbu+alsDMn6ATeg7ZqgMI4OEUfLKuibxP5BV+FzPVIO/KbKtjIn6JPlUYi9EtNbjm5CaiKxyMULgaRfNTNvHA4p4IiUpEhJPEM7rknVmoWwTbmhAV+8scU0TnHnnN6aPnxBGfv7/LebGC9O+KDaQmqcu8/xdhN91ygLk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981163; c=relaxed/simple; bh=4572s9xTVdwUzbQzLlssFdKtKIqWv8RdY2kJgP8ww1A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GW0//neFG/mhD3Nwjf8YCv0oFZKll3Ad+nLlgW0/gOs4lWWhhXxhrkBvFmon3q38kijx6n8mKhqyViE254W81sMQgP+oQOWSWXexMedlbXoO1VfDn+dDnDS5LcMMNxQQsq6ihIKgjQ4zDu79R9kEVgCFIi89VSy5p6VeCrxF1q0= 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=P4Wm1mTD; arc=none smtp.client-ip=209.85.218.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="P4Wm1mTD" Received: by mail-ej1-f45.google.com with SMTP id a640c23a62f3a-c25099bb1fbso232150666b.3 for ; Fri, 28 Aug 2026 22:26:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1787981159; x=1788585959; 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=ztbe6Uhz7Z72lD3H/7iN0kwRmG9muPWYwtlM3Qzlp7I=; b=P4Wm1mTDlCpcdux95bv3Pgjge1uEm+jhDVhd+BG22NooAs/3cVb+C2zRnlAYQujmcC psHCLz3WAM/IcQKxe1l9sDTegfvSZ/D1j7wmAQE8nmq7zgQmkWItZCpxKp/an+ahO8I7 lCc/dsCFuUl7YZF/0KW1K8I+MgWmAD2r+1/lGZJ6BsPRkU3cS9jaiiqufGHzDpDMdsLx p524Gsd+VZiHCwUSWQPiEciIg5ye839Yh3VPrtbyx4ap+tDIBW6jdjIP/i/T/kdGEdd/ 7M0+4AAN0jqUMDciYRFLggRzjURO5Q7ruW/A8hHmc8D8/fqFGDFkVuINICutiEAedl+Q EMYw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787981159; x=1788585959; 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=ztbe6Uhz7Z72lD3H/7iN0kwRmG9muPWYwtlM3Qzlp7I=; b=E93J+jksYFaC3dqcDKy50elMTpzt2zJSH7mweZib4CkfVeBTqThSlk83VBR26DuJpz UcXr2rseeXSrafVAGRy+u1fa3wWc+QZfrpJ2gnMSADyxHb1RJufHFvPenrZ0TKB2MupH jroNYf/A5/x6/k+44RZXRo49ChjNnXHfsuORAhOte61/4+W60zje5HYSkR1uPb8Gxu50 wWS2r+WPLdCX8W/ewsEmRrOKmsiSOpTnyzQcUPb3+MWZhN1g2F1m8x9ireomKESuurdm kFx3zxoKGqMWEw7/+ZgtGK1ch2P3hYlwAk+ZTB/vq9Nya3vBQt3FlFKXvoMiZPlz/OkS 7kQA== X-Forwarded-Encrypted: i=1; AKwUvBxKWPmnsXggQpi3QY0I8JCypzvHHXSXRTg995jiGeOGPW+XST2GQIl57ha0jtxVzMi8Paztq7RZwS/5ZRY=@vger.kernel.org X-Gm-Message-State: AFuF++mxeoFJIP6JYXbJmHq8byQhjwv5XTin/VjGQOqJ/osEDbz+TPfQ UvDpJ5DwLO41HwkfVVqat1tNtBKFGMRkUO8OGPStHgn3x91gJ9QX3LSCmwKApEj4zZETGo74bQG CXvCRc4W46A== X-Gm-Gg: AR+sD10QIvOXpe6jDbYuQYjUDBZcgcixhaZcxZbnAuVfQlHhL9zsm/+4rO+2KR3/Tr+ rKwQZuEO+hbBavosRKYmwEYA5XWIekPIwfPrV0otG0vvQTDO9DtEGKN4xkpNcKNxvDzUraDq9Tu RdH5nPINXf6g7jXblwzx4Q/XOxaaL0Wop57jbDq/W/oHOGISyNyAZ4ACDnHKXTy5j5QoslnpYvp d727HvwNmynVc9yN/H9Eowg8hjLXf2aqfzUR7xhhWdN9zohF60Go/pLZtrGbrIP5jw2eIuQxMJU WM4RvKpUrgDGu7JwJg1M3Uzs7Ja01Ror5Jkg0u2S7AAfxT9DuA94lcufEyMKbpTywcaQQJEPS/R jAC6XxByvVsEoST2tfCkSHS8l0bpskKAfnO1GCqBpTSbneucq4Y+4EWKiIlEk47+x5BzkaoOlTH Xjhog5as/hdbxb6iaDZIkTiYPVmmadUbzV+735Gsa4QA== X-Received: by 2002:a17:907:3e20:b0:c24:d914:6d64 with SMTP id a640c23a62f3a-c255720d399mr799327766b.23.1787981158722; Fri, 28 Aug 2026 22:25:58 -0700 (PDT) Received: from remote-01 ([45.85.105.214]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c255ee75a36sm163750666b.28.2026.08.28.22.25.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2026 22:25:58 -0700 (PDT) From: Aleksei Sviridkin To: netdev@vger.kernel.org Cc: andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Aleksei Sviridkin Subject: [RFC PATCH net-next 3/9] net: phy: air: type the buckpbus core on the bus and address Date: Sat, 29 Aug 2026 05:25:40 +0000 Message-ID: <20260829052546.1152446-4-f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260829052546.1152446-1-f@lex.la> References: <20260829052546.1152446-1-f@lex.la> 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 bus and an address, 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 (mii_bus, addr) and keep the exported phy_device API as page-selecting wrappers around them. The file already carries an mdio_device-typed accessor for the AN8811HB pbus, 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 | 85 +++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/drivers/net/phy/air_phy_lib.c b/drivers/net/phy/air_phy_lib.c index 5141db19fa5e..e0fca5f285d2 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 mii_bus *bus, int addr, 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 __mdiobus_write(bus, addr, 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 __mdiobus_write(bus, addr, 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 __mdiobus_write(bus, addr, 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 __mdiobus_read(bus, addr, 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 __mdiobus_read(bus, addr, 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 mii_bus *bus, int addr, u32 pbus_address, u32 pbus_data) { int ret; =20 - ret =3D __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); + ret =3D __mdiobus_write(bus, addr, 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 __mdiobus_write(bus, addr, 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 __mdiobus_write(bus, addr, 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 __mdiobus_write(bus, addr, 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 __mdiobus_write(bus, addr, 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 mii_bus *bus, int addr, 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 __mdiobus_write(bus, addr, 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 __mdiobus_write(bus, addr, 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 __mdiobus_write(bus, addr, 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 __mdiobus_read(bus, addr, 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 __mdiobus_read(bus, addr, 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 __mdiobus_write(bus, addr, 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 __mdiobus_write(bus, addr, 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 __mdiobus_write(bus, addr, 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 __mdiobus_write(bus, addr, AIR_BPBUS_WR_DATA_LOW, + lower_16_bits(pbus_data_new)); if (ret < 0) return ret; =20 @@ -144,7 +147,9 @@ 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.bus, + phydev->mdio.addr, + pbus_address, pbus_data); if (ret < 0) phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, pbus_address, ret); @@ -163,8 +168,9 @@ 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, - pbus_data); + ret =3D __air_buckpbus_reg_write(phydev->mdio.bus, + phydev->mdio.addr, + pbus_address, pbus_data); if (ret < 0) phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, pbus_address, ret); @@ -183,8 +189,9 @@ 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.bus, + phydev->mdio.addr, + 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 22:00:14 2026 Received: from mail-ej1-f42.google.com (mail-ej1-f42.google.com [209.85.218.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 CF1EB35677E for ; Sat, 29 Aug 2026 05:26:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981167; cv=none; b=gBqtNy0H7UwyzLKglnJQqpNH+b95ni8mO/T7Y6RWt+M1erFgKQo4j2FutwhrhNswFE0TDhnJFSpAR71KM9pbwn8NY78dzjNyQgWIg6NUFZ7340eUqbdmuLHugtdKWMZmr1lVWn6wM7Ar95KBguvC+T1IiEAWQ62NDJTBS1o4Kpo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981167; c=relaxed/simple; bh=aU6OBctWVrxG6oUxcSf2OUD2H5tHnXcJD6peUrom9T8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JuwGABi7XMUO8RbNCZoFG65VEQRDMdxHwumw2k3q6QRK0tRpxpVKIIca24SSiTA7twxUefSz6IonfH3Zpk/1mPYG6WU1jMRJTC6LllgVr+exne3INwxLnlPIy+OkQ/TcYZxVTwm8ZaFKvVCafPYTjruyPf/GAjH74fWcID1Bs0s= 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=dDpPgqKj; arc=none smtp.client-ip=209.85.218.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="dDpPgqKj" Received: by mail-ej1-f42.google.com with SMTP id a640c23a62f3a-c252c7270faso300699066b.3 for ; Fri, 28 Aug 2026 22:26:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1787981161; x=1788585961; 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=ED1uJMv0jD5umM27V202Xvgcpype9EI8mqeysrKe4Ak=; b=dDpPgqKjMgBhYCQBJqaPnoKyv6Nu0Ge7NSvLHTdxQdPeK+dHUVaLLuwjzmr2b38DYo Lp9kPXcZ018ZaN/9CI1cWO2EY6qMtbBX6Ck23vsNoysat0kzG1lM84pzBHxRPjxSG0GP xuVd+GPNV0ZSg9p5MGatqS9p9yxQNAm46KUdtOhyxZ2typyG1Ot7FxxQcPFltVgi93jf boqcjdJ2xRLQ1jVlnfIVOotcwVjmmAcSfe9R+wfT7A5YjmtdIcIYv5tgNkDqFcOuSyNR 3D1z+4dx4D3loY3ieYjyy9/gwF7S8mn8IJGzjfD6y3OVE5GYbYiwRAAZK1mW98Ci+jwR xbIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787981161; x=1788585961; 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=ED1uJMv0jD5umM27V202Xvgcpype9EI8mqeysrKe4Ak=; b=PeWXerN39kFGkguXNp3qg4kRJhvPYzPz5LpOO92hPHeF/heCTMf/V101RWw5FOe8Vj F6o6/9B8Kf/jO2r0zU9GASRhjydPSOoLtpRV0YDlARa/8mBLutnis9erAEge/ZKgWNxt 21MiW2eZgY8AFETge9S4mk+7J2c/nePOYNSTfCoCFJ2n28swylh1MbfBV0E1gNILqy4k eh0GKoOKxeF6grdOXtCODzW/yc/YYhPXUf61zdsBSQUXNnjVD8HVPubMlGY/n2YejZl0 umtm9uw3ywLx+HT8vyTaIHZ6THKopHh4Pgz7t77NWXiva0xShT8TBAIWaspOLbekU5c3 ezYg== X-Forwarded-Encrypted: i=1; AHgh+RpyrGUAO1WoYxyoZpIq3o52HtUNhOyYxRVaPsa+rErFcmRpblJd7k0BQ9HKmdDx/MEsd2TNSXyX0uhPyEw=@vger.kernel.org X-Gm-Message-State: AFuF++ldq51NPu3wjTxv9mhByNFX/M0simDv4lb/GrKWl7BfXLeEj7Bb 50TvfTgYuKqIj+E6HhNDvSHwX/uPk/NdldfDof0lkXTO0iP4XhWdyLj01QIMt153bY4= X-Gm-Gg: AR+sD13QSpK93f1ZdWq4/FeF1MTyKGoxwg5KG6e5YxXNKdm/qr+1El+/Y7uNxYYK5P1 5nzEmaA33epPcP85F76fqSbAbsKTIWoO2FlVPONiQj2nVgVUXBPtn2z56tj12ARahw6mHCT8mhf dJWwzhZKatCmxbXc9ZpcGtuBGiySyTuNABPBfROy+PGlfRGJNP+DU4oxORvzeZEQjhjRnsH+3i2 hRUaWoxcH+7j2uNX1Zx9qnYDyKdUiLFmC3kJO8XlO3IfIxvEYKmZTS3cj/CLheBJNbcaOQTPWrN t4fxQejg8FH5Kr6zIKjUzX6Tkba1rpTYfBP4tU/bxqJi61+U7KE3qxm5SOvKbNNBEC1r06DD/eW 4FXlAbgXiNCa+Q35r2f3Dr4xlwOTUSphPz3BGhXugSgfp+tp4dov/6JFMNq/3x90FDehf4RxTc0 zCAirmhbY2d0nzfcQUjjJc4x58XrYgo5X7O58ELSkBYQ== X-Received: by 2002:a17:907:9810:b0:c25:5114:c832 with SMTP id a640c23a62f3a-c2556bd290bmr844588666b.3.1787981160890; Fri, 28 Aug 2026 22:26:00 -0700 (PDT) Received: from remote-01 ([45.85.105.214]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c255ee75a36sm163750666b.28.2026.08.28.22.25.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2026 22:26:00 -0700 (PDT) From: Aleksei Sviridkin To: netdev@vger.kernel.org Cc: andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Aleksei Sviridkin Subject: [RFC PATCH net-next 4/9] net: phy: air: move the EN8811H firmware download into the library Date: Sat, 29 Aug 2026 05:25:41 +0000 Message-ID: <20260829052546.1152446-5-f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260829052546.1152446-1-f@lex.la> References: <20260829052546.1152446-1-f@lex.la> 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 bus and address like the buckpbus core: the paged transfer, the FW_CTRL sequencing, the MCU-ready wait and the version readout. The bus-level helpers take the MDIO bus lock themselves and save and restore the page register directly, since phy_select_page() needs a phy_device. The MMD status poll goes through mmd_phy_read(), which already handles both C22 indirection and C45. The PHY driver keeps thin wrappers with its old behavior, including the AN8811HB path, which retains its own CRC-checked loader and only shares the paged buffer write. No functional change. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- drivers/net/phy/air_en8811h.c | 143 +----------------- drivers/net/phy/air_phy_lib.c | 268 ++++++++++++++++++++++++++++++++++ drivers/net/phy/air_phy_lib.h | 26 ++++ 3 files changed, 302 insertions(+), 135 deletions(-) diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c index edd49c193e47..fdc64362a565 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,10 @@ static int __air_pbus_reg_write(struct mdio_device *m= diodev, 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.bus, phydev->mdio.addr, + phydev->is_c45, &phydev->mdio.dev); } =20 static int an8811hb_check_crc(struct phy_device *phydev, u32 set1, @@ -405,7 +319,8 @@ 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.bus, phydev->mdio.addr, address, + fw); release_firmware(fw); return ret; } @@ -501,54 +416,12 @@ 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.bus, phydev->mdio.addr, + phydev->is_c45, &phydev->mdio.dev, + &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 e0fca5f285d2..1ed5c69d7073 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 mii_bus *bus, int addr, u32 pbus_address, u32 *pbus_data) @@ -201,6 +206,269 @@ 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 mii_bus *bus, int addr, u32 address, + const struct firmware *fw) +{ + unsigned int offset; + int ret; + u16 val; + + ret =3D __mdiobus_write(bus, addr, AIR_BPBUS_MODE, + AIR_BPBUS_MODE_ADDR_INCR); + if (ret < 0) + return ret; + + ret =3D __mdiobus_write(bus, addr, AIR_BPBUS_WR_ADDR_HIGH, + upper_16_bits(address)); + if (ret < 0) + return ret; + + ret =3D __mdiobus_write(bus, addr, 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 __mdiobus_write(bus, addr, AIR_BPBUS_WR_DATA_HIGH, val); + if (ret < 0) + return ret; + + val =3D get_unaligned_le16(&fw->data[offset]); + ret =3D __mdiobus_write(bus, addr, AIR_BPBUS_WR_DATA_LOW, val); + if (ret < 0) + return ret; + } + + return 0; +} + +/* The phy_select_page() path is not usable here: these run before any + * phy_device exists. Callers hold the bus lock across select/op/restore. + */ +static int air_mdio_select_page(struct mii_bus *bus, int addr, int page) +{ + int saved_page, ret; + + saved_page =3D __mdiobus_read(bus, addr, AIR_EXT_PAGE_ACCESS); + if (saved_page < 0) + return saved_page; + + if (saved_page !=3D page) { + ret =3D __mdiobus_write(bus, addr, AIR_EXT_PAGE_ACCESS, page); + if (ret < 0) + return ret; + } + + return saved_page; +} + +static int air_mdio_restore_page(struct mii_bus *bus, int addr, + int saved_page, int page, int ret) +{ + int restore; + + if (saved_page !=3D page) { + restore =3D __mdiobus_write(bus, addr, AIR_EXT_PAGE_ACCESS, + saved_page); + if (ret >=3D 0 && restore < 0) + ret =3D restore; + } + + return ret; +} + +int air_fw_write_buf(struct mii_bus *bus, int addr, u32 address, + const struct firmware *fw) +{ + int saved_page, ret; + + mutex_lock(&bus->mdio_lock); + + saved_page =3D air_mdio_select_page(bus, addr, AIR_PHY_PAGE_EXTENDED_4); + if (saved_page < 0) { + ret =3D saved_page; + } else { + ret =3D __air_write_buf(bus, addr, address, fw); + ret =3D air_mdio_restore_page(bus, addr, saved_page, + AIR_PHY_PAGE_EXTENDED_4, ret); + } + + mutex_unlock(&bus->mdio_lock); + return ret; +} +EXPORT_SYMBOL_GPL(air_fw_write_buf); + +static int air_mdio_buckpbus_reg_read(struct mii_bus *bus, int addr, + u32 pbus_address, u32 *pbus_data) +{ + int saved_page, ret; + + mutex_lock(&bus->mdio_lock); + + saved_page =3D air_mdio_select_page(bus, addr, AIR_PHY_PAGE_EXTENDED_4); + if (saved_page < 0) { + ret =3D saved_page; + } else { + ret =3D __air_buckpbus_reg_read(bus, addr, pbus_address, + pbus_data); + ret =3D air_mdio_restore_page(bus, addr, saved_page, + AIR_PHY_PAGE_EXTENDED_4, ret); + } + + mutex_unlock(&bus->mdio_lock); + return ret; +} + +static int air_mdio_buckpbus_reg_write(struct mii_bus *bus, int addr, + u32 pbus_address, u32 pbus_data) +{ + int saved_page, ret; + + mutex_lock(&bus->mdio_lock); + + saved_page =3D air_mdio_select_page(bus, addr, AIR_PHY_PAGE_EXTENDED_4); + if (saved_page < 0) { + ret =3D saved_page; + } else { + ret =3D __air_buckpbus_reg_write(bus, addr, pbus_address, + pbus_data); + ret =3D air_mdio_restore_page(bus, addr, saved_page, + AIR_PHY_PAGE_EXTENDED_4, ret); + } + + mutex_unlock(&bus->mdio_lock); + return ret; +} + +static int air_mdio_buckpbus_reg_modify(struct mii_bus *bus, int addr, + u32 pbus_address, u32 mask, u32 set) +{ + int saved_page, ret; + + mutex_lock(&bus->mdio_lock); + + saved_page =3D air_mdio_select_page(bus, addr, AIR_PHY_PAGE_EXTENDED_4); + if (saved_page < 0) { + ret =3D saved_page; + } else { + ret =3D __air_buckpbus_reg_modify(bus, addr, pbus_address, + mask, set); + ret =3D air_mdio_restore_page(bus, addr, saved_page, + AIR_PHY_PAGE_EXTENDED_4, ret); + } + + mutex_unlock(&bus->mdio_lock); + return ret; +} + +static int air_mmd_status_read(struct mii_bus *bus, int addr, bool is_c45) +{ + int ret; + + mutex_lock(&bus->mdio_lock); + ret =3D mmd_phy_read(bus, addr, is_c45, MDIO_MMD_VEND1, + EN8811H_PHY_FW_STATUS); + mutex_unlock(&bus->mdio_lock); + + return ret; +} + +int air_en8811h_wait_mcu_ready(struct mii_bus *bus, int addr, bool is_c45, + struct device *dev) +{ + int ret, reg_value; + + ret =3D air_mdio_buckpbus_reg_write(bus, addr, 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, bus, addr, is_c45); + if (reg_value < 0) + return reg_value; + if (ret) { + dev_err(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 mii_bus *bus, int addr, bool is_c45, + struct device *dev, u32 *fw_version) +{ + const struct firmware *fw1, *fw2; + 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(bus, addr, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_START); + if (ret < 0) + goto air_fw_download_out; + + ret =3D air_mdio_buckpbus_reg_modify(bus, addr, 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(bus, addr, AIR_FW_ADDR_DM, fw1); + if (ret < 0) + goto air_fw_download_out; + + ret =3D air_fw_write_buf(bus, addr, AIR_FW_ADDR_DSP, fw2); + if (ret < 0) + goto air_fw_download_out; + + ret =3D air_mdio_buckpbus_reg_modify(bus, addr, 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(bus, addr, is_c45, dev); + if (ret < 0) + goto air_fw_download_out; + + ret =3D air_mdio_buckpbus_reg_read(bus, addr, 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 here: the callers retry or log on their own terms, + * and a poller retrying a half-installed firmware package would turn + * a print at this level into a permanent drumbeat. + */ + return ret; +} +EXPORT_SYMBOL_GPL(air_en8811h_fw_download); + +MODULE_FIRMWARE(EN8811H_MD32_DM); +MODULE_FIRMWARE(EN8811H_MD32_DSP); + 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..6b11dbeaea9b 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,13 @@ 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 mii_bus *bus, int addr, u32 address, + const struct firmware *fw); +int air_en8811h_wait_mcu_ready(struct mii_bus *bus, int addr, bool is_c45, + struct device *dev); +int air_en8811h_fw_download(struct mii_bus *bus, int addr, bool is_c45, + struct device *dev, u32 *fw_version); + #endif /* __AIR_PHY_LIB_H */ --=20 2.53.0 From nobody Sat Sep 26 22:00:14 2026 Received: from mail-ej1-f44.google.com (mail-ej1-f44.google.com [209.85.218.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EFF74353A9B for ; Sat, 29 Aug 2026 05:26:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981169; cv=none; b=rq+3c1Y9Hygr0HTOr7Gg3N6tMc9/I9qTLtCVAFKgTHdlQVW1KNrmhxdRpw/uQJAvvuxoIqVBZCMLhGdvdiT4TnlTPPaN9QbsL/s85B/XzNs7d/awao2l4Zj4MxG3t3VHkBBxxiwzxDIw9ZiB26VlFrC6hQLa8CpHw9yAv3NrJtQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981169; c=relaxed/simple; bh=yBMJnSe/wEAhqAMpDl5hLrpEj78hz9koYakkvhJfxN4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IE6K4VEeDyRRad1PFSJ2NpujwXBy3zYcwdkDOUGxX46zV+pVJuZGKvl8JDZXfzJ5U/V2awIEL5xTecpJgF4e4vCqwnreBgDsXw2VKKTZGgukNveaj1G1JQC2O/dALFwghNcXCh8T30VhvKLaCR6jiKdlXgl2HviFVVInbyTXIh8= 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=OBxqmdL7; arc=none smtp.client-ip=209.85.218.44 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="OBxqmdL7" Received: by mail-ej1-f44.google.com with SMTP id a640c23a62f3a-c169ae1cb26so567146166b.1 for ; Fri, 28 Aug 2026 22:26:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1787981162; x=1788585962; 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=zmhTKeCBnYxrxfWImIjksOW0xx35+iGmqwjBQ/LHq7E=; b=OBxqmdL7SeNZxPPcnrEy5Q5aSWJqCIjCAFCiwvTpTU0MBCd8SRMbHRK2jznJX1lJgW egYTaHf23LGtf8BW0LZE4I3nT2KNB+/WVhXo9JduSXN4D1/NpmDcIlhPGOFuNbkyrKin TxuuBJ8qleFmwwaI365h3yY31INsUMGsh7tZXNzP9pyUoU35BXH7b9BHQOTFrsHAQc5i J4DDeVsR8k6bSbR0pFTHJB+Aejt2dyCTALlN6QI7zuoOqwx3Svb0vOdFWLZ5Bp5I2iZ1 HK3eCuLXQuOswggVaLdmTwimUSGZXsQSZ9PZUUTqN9TGO4vqVSFy6ZEqHQqhpzZiLmwP /oug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787981162; x=1788585962; 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=zmhTKeCBnYxrxfWImIjksOW0xx35+iGmqwjBQ/LHq7E=; b=knHUy2pwX8YwqjuXAJdZO9OzzAHjKUkhp4eYr4hEXrDjy+7gWU1LOkTdGCkl/92jnM g9Q3iM7v2HT41NpPVVUohOSkoh5zFJBvfQXH9cEpd17nhdmrKg5jTe6hrg9MJHe/2upU U2sXlCF57gvY69uXrYhSB+H0RdIBWdi1r9Dw7HWQKR91lUJEZvlbEvr7ttZ/szkst8K/ DRdUrFBgioS6BUfvGCtv6ZCznMtx/V6vXXCHbjXPpqIHSQ4onpHTe8XfxMWp0v2fy+Vf qWmXVxnVAAPs81e+ut7fhpIfpFLuARYg1bkctah74N3oZo62i2MfZorNodm3R892wKKL iKWA== X-Forwarded-Encrypted: i=1; AHgh+RqmwTstbvjNpHvc3HbjWH4HKbzYpHdGk59PnhmL/kzQK+Glt/D2q75UTMKqdNe8QncvWtRRPBvRMjZZk6M=@vger.kernel.org X-Gm-Message-State: AFuF++kGONFutUbmY4OniybNhHW942+2W+vKyBOOyQzme0yw7n2t4/WA ky4gQCrFSWDhvxA5EdlQP+LCb8dVCaxdIqoZjBe5p3q6RlVcyBoc8jAoaD+Ot4gwYLU= X-Gm-Gg: AR+sD118tybwbWTkwbh2NQty1bfRM2sSgYDeY+yGlZuvPZlhycBEaTvHqgIcagb2pOr XgBo38Q2Quk9swMcfvWT3IERcpoUs+KWPkAsAvnotR1PCmTCR8J1Td0EdfgatWGuhiESjPM8uQd aiIm1a5cW4Oi3rT4sOZwc7mgB3Lj4s5obGbHZsTSCRbZq+8rOUiW1f6yFsR792qQbnsFAfW1/Yy TL9QAUuQtpjiuLPse0CP+OEctXr88CDWwrCpNHnr/M8U4lYANCyibyoM6pk3bOmOJ4UYOll2GZi p7iB6s1a+cgFrQ/JeRkcei3wa3vBVNfAupcpdiiJhS52RVYm6vz21VUOAS2LzIk93Q+QzM7kERk LhmAnK5vzROIcRnuw9rdZFLH4srbCXZvCnLW0f5mDUyZad9H/UeOIRvBbAS5m5Hy6FzXqVH6kW8 Au5B6yye+C5e7W3QvMoTRjVM3S433AO90e2Ylqz2Tjcw== X-Received: by 2002:a17:906:7315:b0:c08:580e:899a with SMTP id a640c23a62f3a-c256ddef826mr325586566b.10.1787981162504; Fri, 28 Aug 2026 22:26:02 -0700 (PDT) Received: from remote-01 ([45.85.105.214]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c255ee75a36sm163750666b.28.2026.08.28.22.26.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2026 22:26:02 -0700 (PDT) From: Aleksei Sviridkin To: netdev@vger.kernel.org Cc: andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Aleksei Sviridkin Subject: [RFC PATCH net-next 5/9] net: phy: air: skip the download when the MD32 is already running Date: Sat, 29 Aug 2026 05:25:42 +0000 Message-ID: <20260829052546.1152446-6-f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260829052546.1152446-1-f@lex.la> References: <20260829052546.1152446-1-f@lex.la> 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 with what it is already running, 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. The wait that follows is what makes this safe: a chip that was not in fact running fails there instead of coming up misprogrammed. Living in the shared helper, the check covers every caller, and it is what lets the PHY driver and the coming MDIO device driver coexist: whichever runs second finds the firmware already up and leaves it alone. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- drivers/net/phy/air_en8811h.c | 5 ++++- drivers/net/phy/air_phy_lib.c | 28 ++++++++++++++++++++++++++++ drivers/net/phy/air_phy_lib.h | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c index fdc64362a565..fcc6e373edd6 100644 --- a/drivers/net/phy/air_en8811h.c +++ b/drivers/net/phy/air_en8811h.c @@ -1030,7 +1030,10 @@ static int en8811h_probe(struct phy_device *phydev) if (ret < 0) return ret; =20 - /* mcu has just restarted after firmware load */ + /* Freshly downloaded firmware has just started; firmware adopted + * from the bootloader is already past its own start. Neither needs + * the restart a later resume would. + */ priv->mcu_needs_restart =3D false; =20 /* MDIO_DEVS1/2 empty, so set mmds_present bits here */ diff --git a/drivers/net/phy/air_phy_lib.c b/drivers/net/phy/air_phy_lib.c index 1ed5c69d7073..c1187f357f4c 100644 --- a/drivers/net/phy/air_phy_lib.c +++ b/drivers/net/phy/air_phy_lib.c @@ -374,6 +374,12 @@ static int air_mmd_status_read(struct mii_bus *bus, in= t addr, bool is_c45) return ret; } =20 +bool air_en8811h_mcu_running(struct mii_bus *bus, int addr, bool is_c45) +{ + return air_mmd_status_read(bus, addr, is_c45) =3D=3D EN8811H_PHY_READY; +} +EXPORT_SYMBOL_GPL(air_en8811h_mcu_running); + int air_en8811h_wait_mcu_ready(struct mii_bus *bus, int addr, bool is_c45, struct device *dev) { @@ -409,6 +415,28 @@ int air_en8811h_fw_download(struct mii_bus *bus, int a= ddr, bool is_c45, const struct firmware *fw1, *fw2; int ret; =20 + if (air_en8811h_mcu_running(bus, addr, is_c45)) { + /* Loaded by a bootloader, an earlier bind, or another + * device serving the chip. The wait below is what makes + * trusting the status register safe: a chip that was not + * in fact running fails there instead of coming up + * misprogrammed. + */ + ret =3D air_en8811h_wait_mcu_ready(bus, addr, is_c45, dev); + if (ret < 0) + return ret; + + ret =3D air_mdio_buckpbus_reg_read(bus, addr, + EN8811H_FW_VERSION, + fw_version); + if (ret < 0) + return ret; + + dev_info(dev, "MD32 already running, firmware %08x\n", + *fw_version); + return 0; + } + 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 6b11dbeaea9b..8d9f24da1271 100644 --- a/drivers/net/phy/air_phy_lib.h +++ b/drivers/net/phy/air_phy_lib.h @@ -59,6 +59,7 @@ struct firmware; =20 int air_fw_write_buf(struct mii_bus *bus, int addr, u32 address, const struct firmware *fw); +bool air_en8811h_mcu_running(struct mii_bus *bus, int addr, bool is_c45); int air_en8811h_wait_mcu_ready(struct mii_bus *bus, int addr, bool is_c45, struct device *dev); int air_en8811h_fw_download(struct mii_bus *bus, int addr, bool is_c45, --=20 2.53.0 From nobody Sat Sep 26 22:00:14 2026 Received: from mail-ed1-f43.google.com (mail-ed1-f43.google.com [209.85.208.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 95C231E22E9 for ; Sat, 29 Aug 2026 05:26:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981170; cv=none; b=c1opa/XbnPIF4ByegVgC603dHfqpk2egpTleAWpUuZRwGSVT2fnIomo8MQ2BOE2CnXFLlFL6Ds0HhH+zpShpI9OeXT1RL3VVDrBqjg15NNXYUdXi7ns7aH3lP26H5t8HfEVh5qqQNj0ubaTV9CAKwBABi8iqHwDxVpzYy13Wp8k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981170; c=relaxed/simple; bh=Om+yIyvp/xVStaLNsNIgsppojGwd8GST4HOKkpGWTXE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jXFaUR45BELMMcaa8xe/m+DjbargfvtujnezR3QpVJ2NeqmOM8tTUJzoaDk22HUwbAAA8bTExoKS6P6DdMQX44IFmc3v3wosu9j829ySmrao6IGJIbz6yuX6PDZ7yqeWdOV1A7A5/mhsrShkbcWDH271abYlZENKQiDpzfVF/DI= 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=en5xdvWR; arc=none smtp.client-ip=209.85.208.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="en5xdvWR" Received: by mail-ed1-f43.google.com with SMTP id 4fb4d7f45d1cf-6a5e971c970so4548203a12.0 for ; Fri, 28 Aug 2026 22:26:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1787981164; x=1788585964; 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=c0I5nG104BUKVRo1dyKSBLkUWSIlwrG3+PtH9GTY9co=; b=en5xdvWRhJ9Htp2xLuSOtMsRzECxVZLyrqah+Gb1GwjHYzXyF0PkmDW/Jv3PlAE67L hkoub2sIkfG0gktlTSWMBZwEUVqiDlL4jjl5dTNYnVgVugCBVmAp/Vy/e0ZJ3iBdGXaN kjh+JmGSe4XrIdFZs3QUIsa4SfrqL9puZGdsP5uZVoT0WETSnhNqDIn/6xConuAJPfJ8 GSuctYj2+dm0LPBgfAvC7RKubU8iHMLSbHwLCv7Q0wLmzB2hqgT67v7uM+JiXsHHVCDZ jyD3TS2uI4ffFYvEc2rhqrVXRMCHxRNW2CxDAlHVvAkEy8Wokywk4PN8TiFBuz6A3lNx yHUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787981164; x=1788585964; 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=c0I5nG104BUKVRo1dyKSBLkUWSIlwrG3+PtH9GTY9co=; b=Gi2iaCRm4FgwMzYKVOpimibUXAJ9HcBDXwXwKSM437BsxblhPaWyYTfHba8yPe7Aou rGm14alzDjTHwScaD6uXZDATVzxejLj8exnVFOzFTbWl7qbZqO2F0QKalxU+oZVlQeU4 DiPUwC2qysJBL+2FHzNYcLHQmQSOwlTTUGTryBJGPYf6fkm3bWps3Qwtn6X8kKKHo9J5 O5DCGu5xo5A4NlruCoo88XIA7o1Somot4ziIq1obJ0PZ6M/aIiGtRZO/16spAH81DLxi D+RgZ+cv/vg8rskB0qxzeNanTamaRztWUUbJH4VtJsk6tFRLSR+8IDo2ueUHljtIZbyD 2uRw== X-Forwarded-Encrypted: i=1; AKwUvBx5+oQpBpEuP0Ot/GFxxthatDx/vFJgnP84m8MXLb/Stq4aOoo1ZS35KCBAHwXHC3ClkkYT9yI+VJpO+k0=@vger.kernel.org X-Gm-Message-State: AFuF++l9JHG/0uMsBmZPaai3IDLR7TKiefkSkhwjh4oORv/91Ik9ukOw UjZUMSy5gKQQYFfIn1ZgFEuYdefZWuMXCF/ltI0afhiZEPWWIGnqdVAr8IaLCyiuxUE= X-Gm-Gg: AR+sD12j9+YD6aVWOoeKZO1Syhzf76wkdRTO/OQNX7mI/qbo7Od4Nvi8Hb7xJ6sAl1V JbxKp4LAPflY6+c6zBWYbmXKdv9abenYyPPAJotby00MuXt6MQIJ+2OGE1lalYJps7iesCiLzwl 4svCr+h8mRJ2+wFdymbxXpLicqE/bGfB4EPKo+YhBNfgz3o6M7fpLNMgAgjnmev9FjKEMdCmcGR WTWLJA0EJO5Y6d/g5DT3qHPbmcCo8q4MnslJlz9q//rvCZRc8Gc6XlBuBI4E88AmLLa6WeWmW2S 8htz8zPA4M7aAbr6HP7Mk7tF8bC/NurpKXFpYmVM3T8mw6+lIOdHsp8d9J/oI2LPLtpwU8ad8z9 YX6EGc2q3ee7OcVUKns7xgEzyyyOWofopSQkfZDk0V/mvbGdDlTw4xX7Qd/Wz4HFPdT+fbXxA6/ +8jW7zCKAH00NAvIWe3rDqpGWfZkKASPbJ2408SZ27JY7exEuC6CLP X-Received: by 2002:a17:907:805:b0:c16:6dac:a008 with SMTP id a640c23a62f3a-c256dda941emr293670266b.8.1787981164124; Fri, 28 Aug 2026 22:26:04 -0700 (PDT) Received: from remote-01 ([45.85.105.214]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c255ee75a36sm163750666b.28.2026.08.28.22.26.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2026 22:26:03 -0700 (PDT) From: Aleksei Sviridkin To: netdev@vger.kernel.org Cc: andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Aleksei Sviridkin Subject: [RFC PATCH net-next 6/9] net: mdio: add Airoha EN8811H MDIO device driver Date: Sat, 29 Aug 2026 05:25:43 +0000 Message-ID: <20260829052546.1152446-7-f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260829052546.1152446-1-f@lex.la> References: <20260829052546.1152446-1-f@lex.la> 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. The driver polls for the firmware files with backoff and downloads through the shared library helper once they can be read; a chip whose firmware was left running by the bootloader is adopted as-is through the helper's running check. There is no give-up path: installing the firmware package on a running system is a normal thing to do, and a driver that had stopped looking would turn that into a needless reboot. The reset line is claimed here rather than on the PHY node, and it is cycled only when the MD32 sits in its bootloader: the 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. Polling is used rather than deferred probing because request_firmware_direct() has no usermode-helper fallback: an unmounted rootfs fails immediately and would keep the deferred-probe list spinning for the whole mount window. 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 | 172 +++++++++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 drivers/net/mdio/mdio-airoha-en8811h.c diff --git a/MAINTAINERS b/MAINTAINERS index 460cb7268845..21d39049e692 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -759,6 +759,13 @@ S: Maintained F: Documentation/devicetree/bindings/net/airoha,en7581-eth.yaml F: drivers/net/ethernet/airoha/ =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 PCIE PHY 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 a05229838cb4..d46bebd05cc8 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..e16211da3d70 --- /dev/null +++ b/drivers/net/mdio/mdio-airoha-en8811h.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Airoha EN8811H MDIO device driver + * + * Until its firmware has been downloaded the EN8811H is not an Ethernet P= HY, + * it is an MD32 microcontroller waiting in its bootloader. Describing it = as a + * plain MDIO device lets the firmware be downloaded as soon as the files = can + * be read - in practice, once the filesystem holding them has been mounte= d - + * and lets the PHY appear only after the chip is able to act as one. + * + * Copyright (C) 2026 Aleksei Sviridkin + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../phy/air_phy_lib.h" + +/* + * Poll rather than defer probing: request_firmware_direct() has no usermo= de + * helper fallback, so a rootfs that is not mounted yet fails immediately = and + * would keep the deferred-probe list spinning for the whole mount window. + * + * Never give up. The firmware can arrive arbitrarily late and still be wo= rth + * waiting for - installing the firmware package on a running system is a + * normal thing to do - and a driver that had stopped looking would turn t= hat + * into a needless reboot. Back off to a slow poll instead, and leave a si= ngle + * breadcrumb for the system that simply does not have the files. + */ +#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; + + /* The chip enumerates as a C22 PHY; MMD access is indirect */ + ret =3D air_en8811h_fw_download(mcu->mdiodev->bus, mcu->mdiodev->addr, + false, dev, &mcu->fw_version); + if (!ret) { + 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) { + /* Missing files resolve by themselves once installed; a bus + * or register error will not, and deserves its own message. + */ + 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)); +} + +static int en8811h_mcu_probe(struct mdio_device *mdiodev) +{ + struct device *dev =3D &mdiodev->dev; + struct en8811h_mcu *mcu; + u32 deassert_us =3D 0; + + mcu =3D devm_kzalloc(dev, sizeof(*mcu), GFP_KERNEL); + if (!mcu) + return -ENOMEM; + + mcu->mdiodev =3D mdiodev; + mdiodev_set_drvdata(mdiodev, mcu); + + /* + * The core only claims reset-gpios for devices flagged as PHYs + * (mdiobus_register_device()), so claim it here. Owning it at this + * level is the point: phy_detach() asserts the reset of the PHY it + * detaches, which would wipe firmware the MD32 holds in RAM. + */ + 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"); + + /* + * Firmware left running by the bootloader, or by a previous bind, + * lives in volatile RAM: the reset line must not be touched then. + * Only a chip still in its bootloader gets the clean reset cycle. + */ + if (air_en8811h_mcu_running(mdiodev->bus, mdiodev->addr, false)) { + dev_dbg(dev, "MD32 already running, adopting it\n"); + } else if (mcu->reset_gpio) { + u32 assert_us =3D 0; + + device_property_read_u32(dev, "reset-assert-us", &assert_us); + device_property_read_u32(dev, "reset-deassert-us", + &deassert_us); + + gpiod_direction_output(mcu->reset_gpio, 1); + if (assert_us) + fsleep(assert_us); + + gpiod_set_value_cansleep(mcu->reset_gpio, 0); + if (deassert_us) + fsleep(deassert_us); + } + + mcu->poll_ms =3D EN8811H_FW_POLL_MIN_MS; + INIT_DELAYED_WORK(&mcu->fw_poll, en8811h_mcu_fw_poll); + /* Freezable, so neither the file lookup nor the ~144KB MDIO + * download can land on a bus that is suspending. The download is + * long for a bound worker, but it runs once per firmware arrival. + */ + 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_DESCRIPTION("Airoha EN8811H MDIO device driver"); +MODULE_AUTHOR("Aleksei Sviridkin "); +MODULE_LICENSE("GPL"); --=20 2.53.0 From nobody Sat Sep 26 22:00:14 2026 Received: from mail-ed1-f45.google.com (mail-ed1-f45.google.com [209.85.208.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 833E22DA749 for ; Sat, 29 Aug 2026 05:26:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981174; cv=none; b=dWWuz4J7eGw1Ig7QY6eorJ1jeFKb58PB2q3nBKDIIxBdiOPd0hgD0eeGHqItmQsfLxTwGAvd1pPrs/o63PIGIITojl2NYqHsgn621bVIDTXB34QWAF/grUArQ7Xex8VWDc6REmH9FkskPs5vm4+oG1kyEs6yXFCp3otZWjNvAyg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981174; c=relaxed/simple; bh=mReJ0qk+WPzQHug/wzwZgzokeoGyjEKDx1oAK0frKb4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bISCqhBuzJyigxRy8E55a7Lh17nQY7sCJ4F2hck+p0MptcGnvyhtlaKje7bYqEoRXLUD+HVP+cHrmjsoIGTODfJCDwiLNv21gfVQjWJFDVD/XEcuhkMjfwFuWubSKoHAA9MgZBT1xyqp05nyzECojrtSoZxkd7zxSVLs6M230MA= 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=asHm3tRA; arc=none smtp.client-ip=209.85.208.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="asHm3tRA" Received: by mail-ed1-f45.google.com with SMTP id 4fb4d7f45d1cf-6a051b737d8so1966612a12.1 for ; Fri, 28 Aug 2026 22:26:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1787981166; x=1788585966; 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=puUVl7pjescZC2ZF+/6D0mZfkH713/A5cm+7yIXo/uY=; b=asHm3tRAHoiEpC9ghGkTDl5b88n4CecWvpmU0rK2CiOBriP0ooN1Zqlv9WmsI8lNAK QtDm3xmrenEQmqFauuN6bK4gbGKNyhllrnCqlKIgrFbc2oz8E3Y1fkhyZE0lC13xC/9P pCDPEnY9nsDKbhcUKnLKduN1SOSQIH1MXk74a4dqPjTmIdWQVniUYng0p+sLeOICYqaS wtLS9BSogrtu9jzzKoZ+M0A8pw7zkLZZo7/tHMo3bxZoiicfOdeQNOph8/+OazpI/UkI D/fSUyvo9U3bBzP5bIqVsvYbFkG3O7AvrauZk6i9bb+yzHIvS0VTq8CJqq9U295beDnL WXWA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787981166; x=1788585966; 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=puUVl7pjescZC2ZF+/6D0mZfkH713/A5cm+7yIXo/uY=; b=IdjKRFE74yo1pBTpk4Ilho4r6bdnVTC7cGg5JiddLxtGOsoP7o1W5SbKN/bUVLe81u dmo8DTIPgrugghwCvsoeZ1kp7it31TOoqQk9ZWpSGUPbmZcY7raXBtqqD2ih922vQeTe tZW+t+tUbqXHVfcVzGmpwd8UfoCmTs6vapSq7tophkNmDJ/QNc69QOrqIV1+o37hG2LN Lhv2TNxLld1ggd0kTeeMsmwjuTDTnBVbHi0hVl/UFsJO42qPYGhtGMR2PzlKLm6VR32m rfkbhiuWOCSgfLeGpRsNAUBecnNPbpSNaqcD4erqIBK2fJOi/ONyZ0ql9Bk8j1XtRzyJ S1Vw== X-Forwarded-Encrypted: i=1; AKwUvBzK1RwyWQE1uv7BaZ49ZHDYPszpxpGpGTKM8xkLtD0yIWFzx4UFaiOBnL46b1e92nX72FGhzXxWJbDfZKs=@vger.kernel.org X-Gm-Message-State: AFuF++mrr8GwWvqmiqaqBc0PE56nXSB9igbb0lnwkUtCJ6HB/pZ70L/S MLF9Rtki40b2E4bYrJUqQY2Mpq5dgdAXWr/WZpn5UAdPxAGplGByq3bBmORFZ4pLmrc= X-Gm-Gg: AYBFou1v1L0h/kiGfMV5YFk2zIwMNCN+J/2VTfYQDI+tZBco7yObRBnXbWoMY+c+AAQ pycPiqnEXPlh5dVF/OvHwMugJqOlLzvunxkqrdSwJWABkQjkraFEBCRLu8yH5gmRXjib4hJs/sg jDHo0N5dptBzCVnX30o78k50PZbScPwH3ks8Uan+itqvUED0zu+cF4oF5wchygqgqsGD6mQV580 uq8/79QZ7w1YcK6r8rAiEgk2k9vnWSwbiU/qjRcsBEfo8svHB6tK0aKFBKlLs05/yV/OkA4eBmV +HRjG2lzaMXZwC2q6z1f4wV8MF7GR5ro8T2+8tggQLWPEnINePpoewzgMEvD8hATA9TUjr6mGXq wILlGLkx+NxdtFWmycZm5u3KyabTsMLgU4T/LAttCqQznvuKUE+TiYTJbussIBvQjS/otO/Y453 PB9tpDhirabXTou6rUY7P8MVT+q3vcr0ThBV1UjBcAhw== X-Received: by 2002:a05:6402:e95:b0:6a6:32fa:1e9c with SMTP id 4fb4d7f45d1cf-6a632fa1f14mr123281a12.20.1787981165662; Fri, 28 Aug 2026 22:26:05 -0700 (PDT) Received: from remote-01 ([45.85.105.214]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c255ee75a36sm163750666b.28.2026.08.28.22.26.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2026 22:26:05 -0700 (PDT) From: Aleksei Sviridkin To: netdev@vger.kernel.org Cc: andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Aleksei Sviridkin Subject: [RFC PATCH net-next 7/9] net: mdio: en8811h: add the nested pass-through bus Date: Sat, 29 Aug 2026 05:25:44 +0000 Message-ID: <20260829052546.1152446-8-f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260829052546.1152446-1-f@lex.la> References: <20260829052546.1152446-1-f@lex.la> 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. Take the parent lock with MDIO_MUTEX_NESTED and use the __mdiobus accessors, which is how 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 | 128 +++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/drivers/net/mdio/mdio-airoha-en8811h.c b/drivers/net/mdio/mdio= -airoha-en8811h.c index e16211da3d70..b28e116289e6 100644 --- a/drivers/net/mdio/mdio-airoha-en8811h.c +++ b/drivers/net/mdio/mdio-airoha-en8811h.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include =20 @@ -47,6 +49,112 @@ struct en8811h_mcu { bool warned; }; =20 +static int en8811h_mcu_read(struct mii_bus *bus, int addr, int regnum) +{ + struct en8811h_mcu *mcu =3D bus->priv; + struct mii_bus *parent =3D mcu->mdiodev->bus; + int ret; + + if (addr !=3D mcu->mdiodev->addr) + return -ENODEV; + + mutex_lock_nested(&parent->mdio_lock, MDIO_MUTEX_NESTED); + ret =3D __mdiobus_read(parent, addr, regnum); + mutex_unlock(&parent->mdio_lock); + + return ret; +} + +static int en8811h_mcu_write(struct mii_bus *bus, int addr, int regnum, u1= 6 val) +{ + struct en8811h_mcu *mcu =3D bus->priv; + struct mii_bus *parent =3D mcu->mdiodev->bus; + int ret; + + if (addr !=3D mcu->mdiodev->addr) + return -ENODEV; + + mutex_lock_nested(&parent->mdio_lock, MDIO_MUTEX_NESTED); + ret =3D __mdiobus_write(parent, addr, regnum, val); + mutex_unlock(&parent->mdio_lock); + + return ret; +} + +static int en8811h_mcu_read_c45(struct mii_bus *bus, int addr, int devad, + int regnum) +{ + struct en8811h_mcu *mcu =3D bus->priv; + struct mii_bus *parent =3D mcu->mdiodev->bus; + int ret; + + if (addr !=3D mcu->mdiodev->addr) + return -ENODEV; + + mutex_lock_nested(&parent->mdio_lock, MDIO_MUTEX_NESTED); + ret =3D __mdiobus_c45_read(parent, addr, devad, regnum); + mutex_unlock(&parent->mdio_lock); + + return ret; +} + +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; + struct mii_bus *parent =3D mcu->mdiodev->bus; + int ret; + + if (addr !=3D mcu->mdiodev->addr) + return -ENODEV; + + mutex_lock_nested(&parent->mdio_lock, MDIO_MUTEX_NESTED); + ret =3D __mdiobus_c45_write(parent, addr, devad, regnum, val); + mutex_unlock(&parent->mdio_lock); + + return ret; +} + +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) { + dev_err(dev, "no mdio node describing the PHY\n"); + return -ENODEV; + } + + bus =3D devm_mdiobus_alloc(dev); + 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; + + 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 devm_of_mdiobus_register(dev, bus, np); + of_node_put(np); + + return ret; +} + static void en8811h_mcu_fw_poll(struct work_struct *work) { struct en8811h_mcu *mcu =3D container_of(to_delayed_work(work), @@ -60,6 +168,15 @@ static void en8811h_mcu_fw_poll(struct work_struct *wor= k) if (!ret) { dev_dbg(dev, "firmware %08x running after %ums\n", mcu->fw_version, mcu->waited_ms); + + /* Unlike a missing firmware file, this does not resolve by + * itself, so unlike the poll there is no retry: surface it + * once and stop. + */ + ret =3D en8811h_mcu_bus_register(mcu); + if (ret) + dev_err(dev, "failed to register the PHY's bus: %pe\n", + ERR_PTR(ret)); return; } =20 @@ -86,6 +203,7 @@ static int en8811h_mcu_probe(struct mdio_device *mdiodev) { struct device *dev =3D &mdiodev->dev; struct en8811h_mcu *mcu; + struct device_node *np; u32 deassert_us =3D 0; =20 mcu =3D devm_kzalloc(dev, sizeof(*mcu), GFP_KERNEL); @@ -95,6 +213,16 @@ static int en8811h_mcu_probe(struct mdio_device *mdiode= v) mcu->mdiodev =3D mdiodev; mdiodev_set_drvdata(mdiodev, mcu); =20 + /* The bus registration only needs this once the firmware runs, but + * a DT hole should fail the bind now, not as a work-item error a + * second after probe already returned success. + */ + 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 only claims reset-gpios for devices flagged as PHYs * (mdiobus_register_device()), so claim it here. Owning it at this --=20 2.53.0 From nobody Sat Sep 26 22:00:14 2026 Received: from mail-ej1-f51.google.com (mail-ej1-f51.google.com [209.85.218.51]) (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 1109935DA47 for ; Sat, 29 Aug 2026 05:26:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981174; cv=none; b=hBtyLJovfoGf3H4ymR/Tl3+ynvtIuLS75ub46wOijWwHIIJwM4lfJX11G+6ObQtMHebY4PMxKK4DkGRrzy9NtFhLWpOU/rPCbMtPGNHKYjXc5y4VT1N8Dd47vX9khi3m6lDVohVg+tWPq1PWS4UxP7GTX+wajJEp32K5zAMJhYU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981174; c=relaxed/simple; bh=Nn4d0wHJqZTPdzNfFzD2yqGS9Q0cS3NqhyFR6MO2xBM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PxsqBdW26HeoymHNXoDji6MAk2XPKsViXOOtBSrBzI7eqYGxeT9WrlH9NwlwN21x1r5g6J0PNB8m+qotQ0it+R0Z0oYx3kLoXg5lkTGTFak9U9arL+OAwyVH+TU3l3Ikb0A9YaNvnFVmPW43OlUWOd31wCYZANSneJ9PkbPH0Lw= 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=JDJvzlCC; arc=none smtp.client-ip=209.85.218.51 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="JDJvzlCC" Received: by mail-ej1-f51.google.com with SMTP id a640c23a62f3a-c20ce3c118aso327417366b.0 for ; Fri, 28 Aug 2026 22:26:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1787981167; x=1788585967; 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=BexHGXJfmWG9wttaxQjMKssISHmEBGNX9tS0o3mB1bs=; b=JDJvzlCCHzaweqCApEYNm3u9o6oXLSw7fbD4X4d00U4rX4h3XZau7IwhOEE6wQ/oZG OXFNGh9z3h4jKdSUcXCjtlrGiLTysDOpkczZLoxFW2RhZ0UgYcJZ1X0KjlkumU9E3jbJ p1s6Red65YAyg3ps5DDucymlNsAX6gUVI0w9vBVWSshGvvYkAy3dtb6+6VNpkmbteuiy i4d0TVSvVtQjlCqBqbZq8AUO5Ubw9+GoxTURWqZWdmpDlDrfR1l/QUvYXtzNLXk0EnYc 0ZV51JuU0bEvT4mV+9/1RMKVr1iH4b4dhmk8dBtBsmSpFYvlchVVERxUywt4opbrhsSF 3VVg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787981167; x=1788585967; 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=BexHGXJfmWG9wttaxQjMKssISHmEBGNX9tS0o3mB1bs=; b=GbJ9Rh48OcFxe5si+XokIvZrb850x6yVflj3OEftObbQorMFLm7GTux9QosOq45Jz4 Vi2lVl1AX/OaxO9pt+TmBnJdj/cjTg9pXoNARNnAS+Kz02A7g00aUoww394Y/4msmNpb D3+Tg2urve6xf+IqMT/pMPxaGtU4ZexOXM4ZVEtZoSulMjhKCJbT4FVsQ7+rEcAntl9y p4Cy+1pJFdAsgAJkgmlCgZwEdcVh2mfpwGtSWEcFuUKJHR7XdgxRQjyzklzfAUbNioJJ Qp4Xc0qQZPQ2kKPFmfsSwkki+NDyraMcAtvVCQIIsh0LXeCHHsrA+zQDInGRhhqNYuEe wx2w== X-Forwarded-Encrypted: i=1; AHgh+Rq1b3y57LXSlh6AxLLcISw/dnjKuOCuRyN1sJ7vgxgWbWkcAteIfCJZ1y6vc2M/xg+tC5QZhYeq6lsQTIQ=@vger.kernel.org X-Gm-Message-State: AFuF++m+QXHhLy1Q01VlHvUsbZR+F8rfI7SFdXhKocruVY/M2P1CRnll tJ2/JfBjACxMcG3utzIBQhiE3CvjbveR0He4k8hswUbswD5FU0/PG799FxGD1ToY/vNpNRoeqWZ KYR15Emamhw== X-Gm-Gg: AYBFou0HUCUetWGAuXO2dI9BbLROpieCfCcS0EnLQfgorW6NJZyISSvKm43UvwM15oI CskIptf1i0hQGJvcWrcSVRSGI22L67WKhKP99ixEAYy29kMeWWKEHtPESqoUAqyH78DZZTkgBhi 7B6hlLJn414awQFs0bNxFg2dDqIDwpSqRb6Ok4Kv8L1CnMGiFVHmYcSxznWtGa24AY1gUxrn7T0 I/Tl/L8JvWLYk8MuefslLOfvDHF1T+Stv79gYAeYFt0Qf685SZCMHDkHlh5XhkEi37bLpByYQd4 G9crlfzoD9F+eLfOMjGAiROynWqYmUIi2sWu4P1kugaXBn8InrXwtSXkUZq6sKRZLnBzOYSDnTa EJi3M0D/8HejLZq4xTczrw6cT9S5dTw7O6K/SL5MDHqQ/U/HsFpdmV9Q9oepDV6DRWnMPCH4sS6 n/M7kF7sdJPkgefiVT3IXFnqGaXhjIG1VqZji5yqiMBQ== X-Received: by 2002:a17:907:1b0e:b0:c1c:2218:f317 with SMTP id a640c23a62f3a-c2535eab9b1mr1470544266b.2.1787981167088; Fri, 28 Aug 2026 22:26:07 -0700 (PDT) Received: from remote-01 ([45.85.105.214]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c255ee75a36sm163750666b.28.2026.08.28.22.26.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2026 22:26:06 -0700 (PDT) From: Aleksei Sviridkin To: netdev@vger.kernel.org Cc: andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Aleksei Sviridkin Subject: [RFC PATCH net-next 8/9] net: phylink: wait for PHYs that are known to probe late Date: Sat, 29 Aug 2026 05:25:45 +0000 Message-ID: <20260829052546.1152446-9-f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260829052546.1152446-1-f@lex.la> References: <20260829052546.1152446-1-f@lex.la> 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 say so with slow-to-probe, and poll for the PHY instead of failing. Returning 0 rather than -ENODEV matters beyond the error itself: DSA reads -ENODEV as permission to go looking for the PHY on the switch's internal MDIO bus, which is the wrong device. Wait for a PHY whose own driver has finished probing, not merely for one that exists. A PHY can be registered long before its driver is, because the driver arrives when userspace gets around to loading it; connecting in between would bind the generic driver, which cannot drive such a PHY and leaves it worse off than not connecting at all. phylink_sfp_connect_phy() already refuses a PHY with no driver for the same reason. Binding alone is not enough either: phy_probe() publishes phydev->drv before it calls the driver's probe, so a PHY caught inside that window is validated against a supported mask that is still empty. Note that this makes slow-to-probe a request for a specific driver: a PHY meant to run on the generic driver must not sit behind the property, because the wait would then never end. A PHY arriving this late has missed phylink_start(), which starts the PHY it finds already attached, so start it here when the port is up. Keep polling after a failed connect, because the errno does not say whether the failure is permanent: phylink_validate_phy() returns -EINVAL both for a PHY that cannot speak the port's interface and for one whose link modes are not in place yet, and only the PHY's driver binding again changes that answer. Giving up would lose the port for good. Back the interval off and report the first failure only, since a retry that reaches bringup detaches the PHY again and phy_detach() asserts its reset line. The poller runs from a workqueue and needs rtnl, while phylink_disconnect_phy() cancels it with rtnl already held, so it takes rtnl with trylock and requeues on failure. For the same reason the synchronous cancel belongs in phylink_destroy(), which documents that rtnl must not be held. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- drivers/net/phy/phylink.c | 202 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 196 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 5b8e956902fb..eda7b61ba5d1 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -73,6 +73,24 @@ struct phylink { struct phylink_link_state phy_state; unsigned int phy_ib_mode; struct work_struct resolve; + /* Set while waiting for a PHY that is expected to probe late. + * Written and read under rtnl only: phylink_disconnect_phy() puts + * and clears it there, which is what makes the poller's dereference + * safe. + */ + struct fwnode_handle *slow_phy_fwnode; + u32 slow_phy_flags; + struct delayed_work slow_phy_poll; + /* Interval before the next poll. Set when the poller is armed and + * thereafter owned by it, since a delayed work never runs twice at + * once. + */ + unsigned int slow_phy_poll_ms; + unsigned int slow_phy_waited_ms; + /* Written under rtnl, read unlocked by the poller; a stale read only + * costs an extra poll cycle. + */ + bool slow_phy_stop; unsigned int pcs_neg_mode; unsigned int pcs_state; =20 @@ -1829,6 +1847,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 +1887,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 +1971,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); } @@ -2201,10 +2226,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 @@ -2242,7 +2265,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 @@ -2254,6 +2277,129 @@ int phylink_connect_phy(struct phylink *pl, struct = phy_device *phy) } EXPORT_SYMBOL_GPL(phylink_connect_phy); =20 +/* How often to re-check whether a late-probing PHY has turned up. */ +#define PHYLINK_SLOW_PHY_POLL_MS 1000 +#define PHYLINK_SLOW_PHY_WARN_MS 60000 + +/* Ceiling that interval backs off to once a connect attempt has failed. */ +#define PHYLINK_SLOW_PHY_POLL_MAX_MS 30000 + +/* A phy-handle has resolved only once it names a device with its own driv= er + * bound. A device that is absent, or present with the generic driver boun= d to + * it, is equally unusable: this is the state slow-to-probe waits out, and= both + * the arming site and the poller must agree on it. + * + * Bound is not probed. phy_probe() assigns phydev->drv before it calls the + * driver's own probe(), and only fills phydev->supported from get_feature= s() + * once that has returned; a device connected in between is validated agai= nst + * an empty link-mode mask. PHY_DOWN is the documented state of a device w= hose + * probe has not completed, and phy_probe() leaves it in PHY_READY. + */ +static bool phylink_phy_is_usable(struct phy_device *phy_dev) +{ + return phy_dev && phy_dev->drv && phy_dev->state !=3D PHY_DOWN && + !phy_driver_is_genphy(phy_dev); +} + +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; + + /* phylink_disconnect_phy() cancels this work while holding rtnl, so + * blocking on rtnl here would deadlock against it. Requeue instead and + * let the canceller finish. + */ + if (!rtnl_trylock()) + goto requeue; + + if (READ_ONCE(pl->slow_phy_stop)) { + rtnl_unlock(); + return; + } + + /* Do not "optimize" the lookup out from under rtnl: rtnl is what + * makes phylink_disconnect_phy()'s put-and-clear of slow_phy_fwnode + * safe against this dereference. The uncontended trylock above is + * cheaper than the use-after-free. + */ + 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); + + /* A PHY that never turns up would otherwise wait in complete + * silence: one breadcrumb after a minute, like the connect + * failure below gets, and like a missing firmware file gets + * from the MDIO side. + */ + 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 the slow-to-probe PHY (%pfw)\n", + pl->slow_phy_fwnode); + rtnl_unlock(); + goto requeue; + } + + if (pl->link_interface =3D=3D PHY_INTERFACE_MODE_NA) { + pl->link_interface =3D phy_dev->interface; + pl->link_config.interface =3D pl->link_interface; + } + + 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 if (!test_bit(PHYLINK_DISABLE_STOPPED, + &pl->phylink_disable_state)) + /* phylink_start() starts the PHY it finds attached, + * and ran long before this one turned up. + */ + phy_start(phy_dev); + } + if (ret) { + /* Whether this is permanent cannot be read off the errno: the + * same -EINVAL comes out of phylink_validate_phy() for a PHY + * that is still filling in its link modes and for one that + * genuinely cannot speak this interface. What decides it is + * the PHY's supported mask, and only the driver binding again + * changes that, so keep polling - giving up here loses the + * port for the lifetime of this phylink. Back off instead: a + * failed bringup ends in phy_detach(), which asserts the PHY's + * reset line. Report the first failure only, so a PHY that + * will never fit costs one line rather than a stream of them. + */ + if (pl->slow_phy_poll_ms =3D=3D PHYLINK_SLOW_PHY_POLL_MS) + phylink_err(pl, "failed to connect late PHY: %pe\n", + ERR_PTR(ret)); + + WRITE_ONCE(pl->slow_phy_poll_ms, + min_t(unsigned int, pl->slow_phy_poll_ms * 2, + PHYLINK_SLOW_PHY_POLL_MAX_MS)); + } + 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 +2428,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 slow-to-probe 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, @@ -2304,6 +2456,32 @@ int phylink_fwnode_phy_connect(struct phylink *pl, } =20 phy_dev =3D fwnode_phy_find_device(phy_fwnode); + if (!phylink_phy_is_usable(phy_dev) && + fwnode_property_present(fwnode, "slow-to-probe")) { + /* The PHY is known to appear late, so keep the node and poll + * for it rather than failing the port for good. Returning an + * error here would also send DSA off to look for the PHY on + * the switch's own MDIO bus. + */ + if (phy_dev) + phy_device_free(phy_dev); + + 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; + WRITE_ONCE(pl->slow_phy_stop, false); + /* mod_ rather than queue_: a poll that a disconnect cancelled + * mid-backoff may still be pending with seconds left on it. + */ + /* Freezable: attaching and starting a PHY has no place in + * the middle of a system suspend transition. + */ + 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) @@ -2345,6 +2523,18 @@ void phylink_disconnect_phy(struct phylink *pl) =20 ASSERT_RTNL(); =20 + /* Cannot cancel synchronously: the poller takes rtnl, which is held. */ + WRITE_ONCE(pl->slow_phy_stop, true); + cancel_delayed_work(&pl->slow_phy_poll); + /* The next connect re-arms from its own fwnode lookup; holding on to + * this one would leak a reference per connect cycle and keep the + * pending state - and its empty-ksettings window - alive on an + * interface whose PHY is long since usable. The poller cannot race + * this: it reads the node only under rtnl, after the stop check. + */ + fwnode_handle_put(pl->slow_phy_fwnode); + pl->slow_phy_fwnode =3D NULL; + mutex_lock(&pl->phydev_mutex); phy =3D pl->phydev; if (phy) { @@ -3730,7 +3920,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 22:00:14 2026 Received: from mail-ej1-f43.google.com (mail-ej1-f43.google.com [209.85.218.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 18D66357D13 for ; Sat, 29 Aug 2026 05:26:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981176; cv=none; b=j8AQrDhbKR4K0bL1L2Ry5a32hBfNJyvU6Fu2xYbXFJYuoS7IHIP7HZ+awOOaAiGmNXZPylXPGTMIu6a3jCjrhyj1SDJEt9cfG9JV80uaGVfEsFC/quYVer9KPagtIFKO576wVWvOgQHFsJ6nwU3jJUxjP/uIByTf49w+Fbg2Duo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787981176; c=relaxed/simple; bh=IrbH0+MeWZS3EtapDOYDSvqhUmoEOkl5mwOPkUGL9QA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gC3cPJ7dEOdmFhs+RXIkMWckmAVtclTpcc+r0ZNN2GL/I4OvC3IBbB11hI1Wbs5vH+g7Zs+Foavyf78nOzXatEUg/gK6uelI77SEuNpyLaESIqjiQ5Jq0fikrGqQwOJVGb/VaUS2sUIognIgekWESzMGbAGU0nLsGJY0pfl7Y1g= 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=ZkpNDnG1; arc=none smtp.client-ip=209.85.218.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="ZkpNDnG1" Received: by mail-ej1-f43.google.com with SMTP id a640c23a62f3a-c25099bb1fbso232156566b.3 for ; Fri, 28 Aug 2026 22:26:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lex.la; s=google; t=1787981169; x=1788585969; 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=ndvJn5dEKLN+yyXRdH9d+TfDQgAC8xbLM6RYflnahZo=; b=ZkpNDnG1+jbjAhKVy7tS8OwZ9MjDPoSz4bAliFawPbD5o+eNk8SNJXH959xIzhv9Pk n/UPK2YJW7Og01NL2fdNEVFTFAnb3HLDS4vsB0njz8nUqDJybWatr8EtOEZqQGahvnRi /KRr5roBjPAmVRlB30MFLZGnDpjNF2Pb0Pq6d6BgWbLLZzi0rzTb3V17GLY4cv89S5uD 0PYLGUWHxCqBn9S8bljATC0LqqMS34/+Z7Jc2t9cu4QrrXc1sEMdB18yItXoeIlTiAV6 frlnWLP99n6ZI0pHne7BlHlV05yeCeu6vd8VV3Y/A9BQASkg5C4zLaQ6clxlEKSMeFTK OgmQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787981169; x=1788585969; 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=ndvJn5dEKLN+yyXRdH9d+TfDQgAC8xbLM6RYflnahZo=; b=TiX1WE0RBtHh13tNtwOHf9K8Uac7HwpO0xo4ysvzHWLNm5H/KiubzS2D7EYCoeLbXo 3PlsVQlkuQxZp934GV7D8xVL5rlYF8Ea2xL92B3l2op5cIxdOBKmFT/urnW2jZEcDkCi GdY7vHu+/azSV/sY/eUwBYB2bGorp+af+YLOXBMAoj9y2nH74X//cXs+x+JZDO8KV3Y9 pJHx8AssQNCtHm3xDZRKLPd6NdueqNhKJVihJ2xtOPx8F8oLtOQOqhBV0DKk/b/W3K6M LQkS3x4nx3mKFXRhjAqH6HeuL38rEzMMYj/Df8hw4q7ZBOPCFyGPPc8tPdyhChGiTc0E aICg== X-Forwarded-Encrypted: i=1; AHgh+RoSlKlySb/ilQxw0+UUcYiEzTPK04+Vqbf+JQ9vFoglQ+k5sNJkZYPoYbn/0F6rktd/hRpXqSEUlKjEV4s=@vger.kernel.org X-Gm-Message-State: AFuF++mTRXEBi95QMm4xj56iCrebGz0mCfJ8eYs2TzD/WPuLXmSXHZGd 2n4+Xik63amC7EKX8dPVFTfgoPsjg0uzQ5B/X0Nzjj1EDJwAccwIQmHoTW4V+foi5Hs= X-Gm-Gg: AR+sD11BpN5PBJEeyFtC0rKABPmjidzy6gkaCgZnUaBqWuRIUHAE58Bt3IF7JjUeCN8 ype5zENSivnvO3IXEWJSuDyzEJctDnUppxkMrXZ2Gy0W3BkEFY2ixE5zXli4+xZnks+zLOat20d xhdTeSdW9rI3BEBD68WrWg5XDcULoynst+e7bAFrsUHeR1R947mUDBseMBZTZGLveiyrc3fjS9B icmW+iFjLxEDHD6qdJlnm+r4eUXsjThI5sIm+j/iV6z5GtzGCt/QhyJ0+3+O9rLB2COCDRn0Sus B5A38NVx1kTbhAtLVSioOoCgLXxNsTkgTq8w3CFKurpQDjZteNDh18g071I4xJoC6zSpK9rArXy MrUZT+Dfn28h1nYydtm0Ir8fNegIyINPxxysFhL+ijjORW4PHsqurIKz7Jbkh5CZgR1tHDJx6jo YhL+dr3ZSIZlYG0pg+lx9C7Ah2BtgUYhNopqkg92q1jFfiPIYXVKtx X-Received: by 2002:a17:906:6a05:b0:c25:608d:7934 with SMTP id a640c23a62f3a-c25608d8c6bmr644259966b.12.1787981168897; Fri, 28 Aug 2026 22:26:08 -0700 (PDT) Received: from remote-01 ([45.85.105.214]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c255ee75a36sm163750666b.28.2026.08.28.22.26.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2026 22:26:08 -0700 (PDT) From: Aleksei Sviridkin To: netdev@vger.kernel.org Cc: andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Aleksei Sviridkin Subject: [RFC PATCH net-next 9/9] net: phylink: report no link modes while a late PHY is missing Date: Sat, 29 Aug 2026 05:25:46 +0000 Message-ID: <20260829052546.1152446-10-f@lex.la> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260829052546.1152446-1-f@lex.la> References: <20260829052546.1152446-1-f@lex.la> 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, matching what an empty SFP cage already does. The EEE calls need no such guard: they already return -EOPNOTSUPP when no PHY is attached. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin --- drivers/net/phy/phylink.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index eda7b61ba5d1..6fbd1fa0be78 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -2284,6 +2284,12 @@ EXPORT_SYMBOL_GPL(phylink_connect_phy); /* Ceiling that interval backs off to once a connect attempt has failed. */ #define PHYLINK_SLOW_PHY_POLL_MAX_MS 30000 =20 +/* True while a PHY declared slow-to-probe has not been connected yet. */ +static bool phylink_slow_phy_pending(struct phylink *pl) +{ + return pl->slow_phy_fwnode && !pl->phydev; +} + /* A phy-handle has resolved only once it names a device with its own driv= er * bound. A device that is absent, or present with the generic driver boun= d to * it, is equally unusable: this is the state slow-to-probe waits out, and= both @@ -3106,6 +3112,17 @@ int phylink_ethtool_ksettings_get(struct phylink *pl, else kset->base.port =3D pl->link_port; =20 + /* Until the PHY arrives the port can do nothing, so report no link + * modes at all rather than the MAC's own capabilities, which is what + * an empty SFP cage reports. + */ + if (phylink_slow_phy_pending(pl)) { + linkmode_zero(kset->link_modes.supported); + kset->base.speed =3D SPEED_UNKNOWN; + kset->base.duplex =3D DUPLEX_UNKNOWN; + return 0; + } + linkmode_copy(kset->link_modes.supported, pl->supported); =20 switch (pl->act_link_an_mode) { @@ -3173,6 +3190,12 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, =20 ASSERT_RTNL(); =20 + /* Without a PHY and without an SFP bus this would configure the MAC + * on its own, for a link that cannot come up yet. + */ + if (phylink_slow_phy_pending(pl)) + return -EINVAL; + if (pl->phydev) { struct ethtool_link_ksettings phy_kset =3D *kset; =20 --=20 2.53.0