From nobody Fri Oct 3 00:03:13 2025 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3818B352FEE; Tue, 9 Sep 2025 15:27:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757431670; cv=none; b=XX1P3EZkQmgQVmOUOJx+DJ7900/ZQbqvlJIaMFyPlivScO4Dba/mtTqF7v3xH5jz/s96LFt8jehuYewfw+ShJ9VPQHZNvaFZFde1Bloln3eWRoargZB1M+KPv7dHPWFr7o8864GE4Wk7QHaxycfyK6HynRT0t/BRGIIpptb6+Lc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757431670; c=relaxed/simple; bh=o5FYh3oTZugN9LT68qVrM5gz/OPBK7ZZw3rN85EunQA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bQefWW7NHzbg4NluSMg+cNVMEMDW7pLcPJu/Px06D8Eg39+dusdeBRBCqDEgc/fIXcj4da9k3b0E7G+gc06fx7WMNKQJZ8kL1zCB/DK2tvjPjBHia5IxRm58MrgqiOEGkYWJkJ3azwuo02+YDIdvHjF1hk/3zWziqc6pk2Ot8jg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=iGEhGuuC; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="iGEhGuuC" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 4A324C6B394; Tue, 9 Sep 2025 15:27:31 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 002F560630; Tue, 9 Sep 2025 15:27:47 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 81548102F28B4; Tue, 9 Sep 2025 17:27:42 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1757431665; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=s4q+SEA1JILehYKkJLFt8JUFivmtIE7L8Bs9yFeUzdQ=; b=iGEhGuuCt+fSYRZ91tqfX/q9s0Jen6eOnvIRm32d5D/iQF+UzD4S1fdYipjSztGQFVCmoz mBTqyD+jQzdBxoIavK531VksHXEh9btxzwheB0qzCDDhdKFnXV33cyVSDvNv+zUr2Bm+SN a7Iw89XRl2C10g1mLhw/WgtLR1BJT5oLMwYU8Wj2SIDEfKW3QAJ4mHcEAkGGIU47bFH/M0 5/bcKnI5QZqKT+t6iMO2rHi0ycmlcUdlxHqRHcAG5h9Q6Ksrq7M+SrX9Not/YlI7E2bCRQ f/28N6jql6w90qcj1FP0efuL/LYFAhYfPnpGR1bkX4bz6PJdz/t3HqGuIYqBoA== From: Maxime Chevallier To: davem@davemloft.net Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, thomas.petazzoni@bootlin.com, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , linux-arm-kernel@lists.infradead.org, Christophe Leroy , Herve Codina , Florian Fainelli , Heiner Kallweit , Vladimir Oltean , =?UTF-8?q?K=C3=B6ry=20Maincent?= , =?UTF-8?q?Marek=20Beh=C3=BAn?= , Oleksij Rempel , =?UTF-8?q?Nicol=C3=B2=20Veronese?= , Simon Horman , mwojtas@chromium.org, Antoine Tenart , devicetree@vger.kernel.org, Conor Dooley , Krzysztof Kozlowski , Rob Herring , Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next v12 09/18] net: phylink: Move sfp interface selection and filtering to phy_caps Date: Tue, 9 Sep 2025 17:26:05 +0200 Message-ID: <20250909152617.119554-10-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250909152617.119554-1-maxime.chevallier@bootlin.com> References: <20250909152617.119554-1-maxime.chevallier@bootlin.com> 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 X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" Phylink's helpers to get the interfaces usable on an SFP module based on speed and linkmodes can be modes to phy_caps, so that it can benefit to PHY-driver SFP support. Signed-off-by: Maxime Chevallier Reviewed-by: Christophe Leroy --- drivers/net/phy/phy-caps.h | 6 ++++ drivers/net/phy/phy_caps.c | 72 ++++++++++++++++++++++++++++++++++++++ drivers/net/phy/phylink.c | 72 +++++--------------------------------- 3 files changed, 86 insertions(+), 64 deletions(-) diff --git a/drivers/net/phy/phy-caps.h b/drivers/net/phy/phy-caps.h index ba81cd75e122..ebed340a2e77 100644 --- a/drivers/net/phy/phy-caps.h +++ b/drivers/net/phy/phy-caps.h @@ -66,4 +66,10 @@ void phy_caps_medium_get_supported(unsigned long *suppor= ted, int lanes); u32 phy_caps_mediums_from_linkmodes(unsigned long *linkmodes); =20 +void phy_caps_filter_sfp_interfaces(unsigned long *dst, + const unsigned long *interfaces); +phy_interface_t phy_caps_select_sfp_interface_speed(const unsigned long *i= nterfaces, + u32 speed); +phy_interface_t phy_caps_choose_sfp_interface(const unsigned long *interfa= ces); + #endif /* __PHY_CAPS_H */ diff --git a/drivers/net/phy/phy_caps.c b/drivers/net/phy/phy_caps.c index b38c567ec6ef..e4adc36e0fe3 100644 --- a/drivers/net/phy/phy_caps.c +++ b/drivers/net/phy/phy_caps.c @@ -63,6 +63,22 @@ static int speed_duplex_to_capa(int speed, unsigned int = duplex) #define for_each_link_caps_desc_speed(cap) \ for (cap =3D &link_caps[__LINK_CAPA_MAX - 1]; cap >=3D link_caps; cap--) =20 +static const phy_interface_t phy_caps_sfp_interface_preference[] =3D { + PHY_INTERFACE_MODE_100GBASEP, + PHY_INTERFACE_MODE_50GBASER, + PHY_INTERFACE_MODE_LAUI, + PHY_INTERFACE_MODE_25GBASER, + PHY_INTERFACE_MODE_USXGMII, + PHY_INTERFACE_MODE_10GBASER, + PHY_INTERFACE_MODE_5GBASER, + PHY_INTERFACE_MODE_2500BASEX, + PHY_INTERFACE_MODE_SGMII, + PHY_INTERFACE_MODE_1000BASEX, + PHY_INTERFACE_MODE_100BASEX, +}; + +static DECLARE_PHY_INTERFACE_MASK(phy_caps_sfp_interfaces); + /** * phy_caps_init() - Initializes the link_caps array from the link_mode_pa= rams. * @@ -100,6 +116,10 @@ int phy_caps_init(void) __set_bit(i, link_caps[capa].linkmodes); } =20 + for (int i =3D 0; i < ARRAY_SIZE(phy_caps_sfp_interface_preference); ++i) + __set_bit(phy_caps_sfp_interface_preference[i], + phy_caps_sfp_interfaces); + return 0; } =20 @@ -520,3 +540,55 @@ int phy_caps_interface_max_speed(phy_interface_t inter= face) return SPEED_UNKNOWN; } EXPORT_SYMBOL_GPL(phy_caps_interface_max_speed); + +void phy_caps_filter_sfp_interfaces(unsigned long *dst, + const unsigned long *interfaces) +{ + phy_interface_and(dst, interfaces, phy_caps_sfp_interfaces); +} + +phy_interface_t +phy_caps_select_sfp_interface_speed(const unsigned long *interfaces, u32 s= peed) +{ + phy_interface_t best_interface =3D PHY_INTERFACE_MODE_NA; + phy_interface_t interface; + u32 max_speed; + int i; + + for (i =3D 0; i < ARRAY_SIZE(phy_caps_sfp_interface_preference); i++) { + interface =3D phy_caps_sfp_interface_preference[i]; + if (!test_bit(interface, interfaces)) + continue; + + max_speed =3D phy_caps_interface_max_speed(interface); + + /* The logic here is: if speed =3D=3D max_speed, then we've found + * the best interface. Otherwise we find the interface that + * can just support the requested speed. + */ + if (max_speed >=3D speed) + best_interface =3D interface; + + if (max_speed <=3D speed) + break; + } + + return best_interface; +} +EXPORT_SYMBOL_GPL(phy_caps_select_sfp_interface_speed); + +phy_interface_t phy_caps_choose_sfp_interface(const unsigned long *interfa= ces) +{ + phy_interface_t interface; + size_t i; + + interface =3D PHY_INTERFACE_MODE_NA; + for (i =3D 0; i < ARRAY_SIZE(phy_caps_sfp_interface_preference); i++) + if (test_bit(phy_caps_sfp_interface_preference[i], interfaces)) { + interface =3D phy_caps_sfp_interface_preference[i]; + break; + } + + return interface; +} +EXPORT_SYMBOL_GPL(phy_caps_choose_sfp_interface); diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 091b1ee5c49a..91111ea1b149 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -126,22 +126,6 @@ do { \ }) #endif =20 -static const phy_interface_t phylink_sfp_interface_preference[] =3D { - PHY_INTERFACE_MODE_100GBASEP, - PHY_INTERFACE_MODE_50GBASER, - PHY_INTERFACE_MODE_LAUI, - PHY_INTERFACE_MODE_25GBASER, - PHY_INTERFACE_MODE_USXGMII, - PHY_INTERFACE_MODE_10GBASER, - PHY_INTERFACE_MODE_5GBASER, - PHY_INTERFACE_MODE_2500BASEX, - PHY_INTERFACE_MODE_SGMII, - PHY_INTERFACE_MODE_1000BASEX, - PHY_INTERFACE_MODE_100BASEX, -}; - -static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces); - /** * phylink_set_port_modes() - set the port type modes in the ethtool mask * @mask: ethtool link mode mask @@ -1922,8 +1906,7 @@ static int phylink_validate_phy(struct phylink *pl, s= truct phy_device *phy, /* If the PHY is on a SFP, limit the interfaces to * those that can be used with a SFP module. */ - phy_interface_and(interfaces, interfaces, - phylink_sfp_interfaces); + phy_caps_filter_sfp_interfaces(interfaces, interfaces); =20 if (phy_interface_empty(interfaces)) { phylink_err(pl, "SFP PHY's possible interfaces becomes empty\n"); @@ -2643,34 +2626,16 @@ static phy_interface_t phylink_sfp_select_interface= (struct phylink *pl, static phy_interface_t phylink_sfp_select_interface_speed(struct phylink *= pl, u32 speed) { - phy_interface_t best_interface =3D PHY_INTERFACE_MODE_NA; phy_interface_t interface; - u32 max_speed; - int i; - - for (i =3D 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++) { - interface =3D phylink_sfp_interface_preference[i]; - if (!test_bit(interface, pl->sfp_interfaces)) - continue; - - max_speed =3D phy_caps_interface_max_speed(interface); =20 - /* The logic here is: if speed =3D=3D max_speed, then we've found - * the best interface. Otherwise we find the interface that - * can just support the requested speed. - */ - if (max_speed >=3D speed) - best_interface =3D interface; - - if (max_speed <=3D speed) - break; - } + interface =3D phy_caps_select_sfp_interface_speed(pl->sfp_interfaces, + speed); =20 - if (best_interface =3D=3D PHY_INTERFACE_MODE_NA) + if (interface =3D=3D PHY_INTERFACE_MODE_NA) phylink_err(pl, "selection of interface failed, speed %u\n", speed); =20 - return best_interface; + return interface; } =20 static void phylink_merge_link_mode(unsigned long *dst, const unsigned lon= g *b) @@ -3450,17 +3415,7 @@ static void phylink_sfp_detach(void *upstream, struc= t sfp_bus *bus) static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl, const unsigned long *intf) { - phy_interface_t interface; - size_t i; - - interface =3D PHY_INTERFACE_MODE_NA; - for (i =3D 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++) - if (test_bit(phylink_sfp_interface_preference[i], intf)) { - interface =3D phylink_sfp_interface_preference[i]; - break; - } - - return interface; + return phy_caps_choose_sfp_interface(intf); } =20 static void phylink_sfp_set_config(struct phylink *pl, unsigned long *supp= orted, @@ -3737,8 +3692,8 @@ static int phylink_sfp_connect_phy(void *upstream, st= ruct phy_device *phy) phy_support_asym_pause(phy); =20 /* Set the PHY's host supported interfaces */ - phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces, - pl->config->supported_interfaces); + phy_caps_filter_sfp_interfaces(phy->host_interfaces, + pl->config->supported_interfaces); =20 /* Do the initial configuration */ return phylink_sfp_config_phy(pl, phy); @@ -4166,16 +4121,5 @@ void phylink_mii_c45_pcs_get_state(struct mdio_devic= e *pcs, } EXPORT_SYMBOL_GPL(phylink_mii_c45_pcs_get_state); =20 -static int __init phylink_init(void) -{ - for (int i =3D 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); ++i) - __set_bit(phylink_sfp_interface_preference[i], - phylink_sfp_interfaces); - - return 0; -} - -module_init(phylink_init); - MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("phylink models the MAC to optional PHY connection"); --=20 2.49.0