From nobody Sat Feb 7 12:34:43 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 5805235A92F; Tue, 27 Jan 2026 13:42:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521345; cv=none; b=LxEEQ13q3/1er7//cBWyGMNazFTJvYwk87GeP1dyiwlGPy9M8ddLjRxZr7W7jbgaiH/XwHkL0W5Y4YsZffjCLpOcNtKFoZo4SB4xiGJx3lve6bNgnAWMp7jaF08RqhmOT0Mo+wls9WpufcLn77VfISConW4aYtyMNOogpjpflfE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521345; c=relaxed/simple; bh=2x2Twk5hwB1qm9MtsaxYrP7i5T6qH8pGMbiXcSTMo1s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=V8gt5fYCg/6r4AL5JvLTPfHlBWlNctYBrL/vb+yuSa826RMcsRSIZXJ3GQoCiAvLlDHbRNHWfyP660VF8kR2fxun7eZ1En8OvFtW7svWe1GTq7PeRMyvls8cK6nqesPtqDwJelHMPHkEPZSbn7rqkRsQ6qN/EqjArHdO7K5G0Po= 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=ERgLyxk/; arc=none smtp.client-ip=185.246.85.4 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="ERgLyxk/" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id E174B4E422D3; Tue, 27 Jan 2026 13:42:21 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id B3AAE606F5; Tue, 27 Jan 2026 13:42:21 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id B7E05119A864D; Tue, 27 Jan 2026 14:42:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769521340; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=vnp5YkIChB0sNg7EdJ/lX1dIvAkP9AXfzZTaTC0ju30=; b=ERgLyxk/5cmi2bot+No+wtGGZE0g/ywwL/+/lcGKD5S/C9Fa3jCHezTdFd4mmuvELVvlp2 kDurb/3NW2FI/WlKgZcVA6z8hkXw/rT9M1P60iGmzjALfJh808CntD+soTDjb38gZzrjJ7 D1u5bh7/ziXSekJQIO6gBBsn5hszeIG977xaqFsQm8pwY6mWuQfbUapUYVlhvEyeUnbDFT RxUv9KYoKOzTEl3nCwd88rlwzidzGBZtiI5wjkN3a4txV3JUPCEyKerj9bfhCPlcu2sPJg wLtpcIpa0yaEtTJZHyBoN5qyjk5eSeUANQ9r4fxr7KS7V3qRtV0B4jqpHYAvhw== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , 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, Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next 01/13] net: phy: phy_port: Correctly recompute the port's linkmodes Date: Tue, 27 Jan 2026 14:41:49 +0100 Message-ID: <20260127134202.8208-2-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260127134202.8208-1-maxime.chevallier@bootlin.com> References: <20260127134202.8208-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" a PHY-driven phy_port contains a 'supported' field containing the linkmodes available on this port. This is populated based on : - The PHY's reported features - The DT representation of the connector - The PHY's attach_mdi() callback As these different attrbutin methods work in conjunction, the helper phy_port_update_supported() recomputes the final 'supported' value based on the populated mediums, linkmodes and pairs. However this recompute wasn't correctly implemented, and added more modes than necessary by or'ing the medium-specific modes to the existing support. Let's fix this and properly filter the modes. Fixes: 589e934d2735 ("net: phy: Introduce PHY ports representation") Signed-off-by: Maxime Chevallier --- drivers/net/phy/phy_port.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/phy_port.c b/drivers/net/phy/phy_port.c index ec93c8ca051e..68a0068220ed 100644 --- a/drivers/net/phy/phy_port.c +++ b/drivers/net/phy/phy_port.c @@ -118,11 +118,14 @@ void phy_port_update_supported(struct phy_port *port) int i; =20 for_each_set_bit(i, &port->mediums, __ETHTOOL_LINK_MEDIUM_LAST) { - linkmode_zero(supported); - phy_caps_medium_get_supported(supported, i, port->pairs); - linkmode_or(port->supported, port->supported, supported); + __ETHTOOL_DECLARE_LINK_MODE_MASK(med_supported) =3D {0}; + + phy_caps_medium_get_supported(med_supported, i, port->pairs); + linkmode_or(supported, supported, med_supported); } =20 + linkmode_and(port->supported, port->supported, supported); + /* If there's no pairs specified, we grab the default number of * pairs as the max of the default pairs for each linkmode */ --=20 2.49.0 From nobody Sat Feb 7 12:34:43 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 13AAA35B622; Tue, 27 Jan 2026 13:42:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521347; cv=none; b=AzflACl39WoiwM8RtQq4cy0mtQzQDjU7pWDZEQdiDqFR1kZwD7xTRufUyarrZbe9DDPj4hdqNCszDDLOsnGzVBcJqzoSCFX/0Vy3WN1poJX+k+t7kghulFLG7K0bbTw575cGYXku/kuldWfXUZ4gsPskpMZeFWhg3auyTWNYrwk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521347; c=relaxed/simple; bh=FzfPssaMTtMlTXsQB3uWK2d1KPWw1AhO9CiOrY0mA4o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BnLrEJ4Fx/1HncIOtRweSBxasxPYTrQL/19Qg871X6KYMySV2d/a9D/+0p6k73SwJwNUlvgNzzlcGP2Bybj6PDwFyueVqMQ8FYNvNU94ydVDvHJtwVnogwYExHRlNBpbwB6bqIOSUK8I146+rc019Lc5BAAE6c5A26vb6MsywfI= 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=0bcWBkK0; arc=none smtp.client-ip=185.246.85.4 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="0bcWBkK0" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 932FC4E422D4; Tue, 27 Jan 2026 13:42:24 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 68B0D606F5; Tue, 27 Jan 2026 13:42:24 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 081DA119A867D; Tue, 27 Jan 2026 14:42:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769521343; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=LWzrt0LzFGZIeHx1tJakp6EzeCmz9kccT2ixoT2csH8=; b=0bcWBkK01Es7e2AMsLv2DZO2aORDLF4HRcyc2KAFNQfu0FoQrS7yIfHu3xfqOMgf4I+w8d 3zcr9Gd4oME3MFDgNxLo8Cj99mpAjW/KaSXfZDurNJLeIK/ueAs6HS8WGEyy4keFR2ZO9u K0QMQ7KB8eyQcD7iKljcX8ni6IsCUmewxxHbqgV5Fzx7/WBkRkHHc8vTCgROkEofoZUQeo 48VvMjoC4mYvb+XlqKmJsGaxNEqcca4R/WAmTCMYhimUdvGIv079a+Cv4NAvrOcEt896Ce UEeuVYzfZAmr0dISNPeV/AZJJoP55/AI1bmluOKDJOk8yhWEykiwn/+CjOn3vw== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , 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, Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next 02/13] net: phy: phy_link_topology: Add a helper for opportunistic alloc Date: Tue, 27 Jan 2026 14:41:50 +0100 Message-ID: <20260127134202.8208-3-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260127134202.8208-1-maxime.chevallier@bootlin.com> References: <20260127134202.8208-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" The phy_link_topology structure stores information about the PHY-related components connected to a net_device. It is opportunistically allocated, when we add the first item to the topology, as this is not relevant for all kinds of net_devices. In preparation for the addition of phy_port tracking in the topology, let's make a dedicated helper for that allocation sequence. Signed-off-by: Maxime Chevallier --- drivers/net/phy/phy_link_topology.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/net/phy/phy_link_topology.c b/drivers/net/phy/phy_link= _topology.c index 0e9e987f37dd..7dc2ff10c74a 100644 --- a/drivers/net/phy/phy_link_topology.c +++ b/drivers/net/phy/phy_link_topology.c @@ -27,21 +27,34 @@ static int netdev_alloc_phy_link_topology(struct net_de= vice *dev) return 0; } =20 +static struct phy_link_topology *phy_link_topo_get_or_alloc(struct net_dev= ice *dev) +{ + int ret; + + if (dev->link_topo) + return dev->link_topo; + + /* The topology is allocated the first time we add an object to it. + * It is freed alongside the netdev. + */ + ret =3D netdev_alloc_phy_link_topology(dev); + if (ret) + return ERR_PTR(ret); + + return dev->link_topo; +} + int phy_link_topo_add_phy(struct net_device *dev, struct phy_device *phy, enum phy_upstream upt, void *upstream) { - struct phy_link_topology *topo =3D dev->link_topo; + struct phy_link_topology *topo; struct phy_device_node *pdn; int ret; =20 - if (!topo) { - ret =3D netdev_alloc_phy_link_topology(dev); - if (ret) - return ret; - - topo =3D dev->link_topo; - } + topo =3D phy_link_topo_get_or_alloc(dev); + if (IS_ERR(topo)) + return PTR_ERR(topo); =20 pdn =3D kzalloc(sizeof(*pdn), GFP_KERNEL); if (!pdn) --=20 2.49.0 From nobody Sat Feb 7 12:34:43 2026 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 4689835A937 for ; Tue, 27 Jan 2026 13:42:28 +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=1769521350; cv=none; b=La9MtzHEk2wOkgYBUlvP8dsWVYvyl11YIUGLuPZ8EZnM2P93HVBsRKEPf8NHDVO/yuVdh1oRh26/HvLAOo7qxGK31bQcpKpqVJD0ZtkbJi5jLeTFQOE3jLxUlekg+TjeWJ4z6bYQ5YpsSGrHcA0ZFDjsOVkzyUkFPsqxqDU/FJc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521350; c=relaxed/simple; bh=zG7c4zea8VE4V219ZZVeP2fM4wO1cr7BMyScZTzoeKU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=U+kAKjKHPuNjoq9r3o/YOvECUM1IxzA0JbS8BhWSrKMM1gv/+yqOeRGBWSg26gSNzIGi8OvNyEKr9d7Ah8ugZmwEt2iCJk8bCPX3OIOSf2JEjRqJNmUHWEKn9XO/Prw5IW2nhSMV7aUKWuiLwz6GU76lEwr6EsLOUMBXVtaYREg= 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=HB8BaaQO; 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="HB8BaaQO" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id DB40AC211C0; Tue, 27 Jan 2026 13:42:28 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id CA526606F5; Tue, 27 Jan 2026 13:42:26 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 878FE119A868A; Tue, 27 Jan 2026 14:42:23 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769521345; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=2SISv38DICV1ZK5752rVTWKc+HfCfzGYVgx0PBc7Ulw=; b=HB8BaaQOj+fLHTpeennJZu7fBtvILTc4SpQhoxEwRoU+jqutUK0JpLi3SEKlqScTXlAiCo oFUp14LKaiIgSwe5Y102bZNz3L2Zcmb52sgpgHair5cs8Uuhc8zJKTXmiTjsPpb6QzJcdW 3/Dpg5BymdoWDrgiaUvpR2JjFfyHDsL7ypOGFu8iKSyq8F9zR0N+0PVxhunUQk7euJbJip VJXEbvQMeqLt2IGQHkUgtMadcczD/AHKZ+LT22033ryFKjJjDVY5rz6V14aZijV8owyW2w +EZSOzXiOQTA66SdMk65JYdTStAvFNZTJS7GFcdOQfXqlHLlIRkjyXwwsBsXtA== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , 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, Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next 03/13] net: phy: phy_link_topology: Track ports in phy_link_topology Date: Tue, 27 Jan 2026 14:41:51 +0100 Message-ID: <20260127134202.8208-4-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260127134202.8208-1-maxime.chevallier@bootlin.com> References: <20260127134202.8208-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" phy_port is aimed at representing the various physical interfaces of a net_device. They can be controlled by various components in the link, such as the Ethernet PHY, the Ethernet MAC, and SFP module, etc. Let's therefore make so we keep track of all the ports connected to a netdev in phy_link_topology. The only ports added for now are phy-driven ports. Signed-off-by: Maxime Chevallier --- drivers/net/phy/phy_link_topology.c | 51 +++++++++++++++++++++++++++++ include/linux/phy_link_topology.h | 18 ++++++++++ include/linux/phy_port.h | 2 ++ 3 files changed, 71 insertions(+) diff --git a/drivers/net/phy/phy_link_topology.c b/drivers/net/phy/phy_link= _topology.c index 7dc2ff10c74a..a063a706e833 100644 --- a/drivers/net/phy/phy_link_topology.c +++ b/drivers/net/phy/phy_link_topology.c @@ -7,6 +7,7 @@ */ =20 #include +#include #include #include #include @@ -22,6 +23,9 @@ static int netdev_alloc_phy_link_topology(struct net_devi= ce *dev) xa_init_flags(&topo->phys, XA_FLAGS_ALLOC1); topo->next_phy_index =3D 1; =20 + xa_init_flags(&topo->ports, XA_FLAGS_ALLOC1); + topo->next_port_index =3D 1; + dev->link_topo =3D topo; =20 return 0; @@ -44,12 +48,45 @@ static struct phy_link_topology *phy_link_topo_get_or_a= lloc(struct net_device *d return dev->link_topo; } =20 +int phy_link_topo_add_port(struct net_device *dev, struct phy_port *port) +{ + struct phy_link_topology *topo; + int ret; + + topo =3D phy_link_topo_get_or_alloc(dev); + if (IS_ERR(topo)) + return PTR_ERR(topo); + + /* Attempt to re-use a previously allocated port_id */ + if (port->id) + ret =3D xa_insert(&topo->ports, port->id, port, GFP_KERNEL); + else + ret =3D xa_alloc_cyclic(&topo->ports, &port->id, port, + xa_limit_32b, &topo->next_port_index, + GFP_KERNEL); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_link_topo_add_port); + +void phy_link_topo_del_port(struct net_device *dev, struct phy_port *port) +{ + struct phy_link_topology *topo =3D dev->link_topo; + + if (!topo) + return; + + xa_erase(&topo->ports, port->id); +} +EXPORT_SYMBOL_GPL(phy_link_topo_del_port); + int phy_link_topo_add_phy(struct net_device *dev, struct phy_device *phy, enum phy_upstream upt, void *upstream) { struct phy_link_topology *topo; struct phy_device_node *pdn; + struct phy_port *port; int ret; =20 topo =3D phy_link_topo_get_or_alloc(dev); @@ -89,8 +126,18 @@ int phy_link_topo_add_phy(struct net_device *dev, if (ret < 0) goto err; =20 + /* Add all the PHY's ports to the topology */ + list_for_each_entry(port, &phy->ports, head) { + ret =3D phy_link_topo_add_port(dev, port); + if (ret) + goto del_ports; + } + return 0; =20 +del_ports: + list_for_each_entry_from_reverse(port, &phy->ports, head) + phy_link_topo_del_port(dev, port); err: kfree(pdn); return ret; @@ -102,10 +149,14 @@ void phy_link_topo_del_phy(struct net_device *dev, { struct phy_link_topology *topo =3D dev->link_topo; struct phy_device_node *pdn; + struct phy_port *port; =20 if (!topo) return; =20 + list_for_each_entry(port, &phy->ports, head) + phy_link_topo_del_port(dev, port); + pdn =3D xa_erase(&topo->phys, phy->phyindex); =20 /* We delete the PHY from the topology, however we don't re-set the diff --git a/include/linux/phy_link_topology.h b/include/linux/phy_link_top= ology.h index 68a59e25821c..66bceff72b19 100644 --- a/include/linux/phy_link_topology.h +++ b/include/linux/phy_link_topology.h @@ -16,11 +16,15 @@ =20 struct xarray; struct phy_device; +struct phy_port; struct sfp_bus; =20 struct phy_link_topology { struct xarray phys; u32 next_phy_index; + + struct xarray ports; + u32 next_port_index; }; =20 struct phy_device_node { @@ -43,6 +47,9 @@ int phy_link_topo_add_phy(struct net_device *dev, =20 void phy_link_topo_del_phy(struct net_device *dev, struct phy_device *phy); =20 +int phy_link_topo_add_port(struct net_device *dev, struct phy_port *port); +void phy_link_topo_del_port(struct net_device *dev, struct phy_port *port); + static inline struct phy_device * phy_link_topo_get_phy(struct net_device *dev, u32 phyindex) { @@ -72,6 +79,17 @@ static inline void phy_link_topo_del_phy(struct net_devi= ce *dev, { } =20 +static inline int phy_link_topo_add_port(struct net_device *dev, + struct phy_port *port) +{ + return 0; +} + +static inline void phy_link_topo_del_port(struct net_device *dev, + struct phy_port *port) +{ +} + static inline struct phy_device * phy_link_topo_get_phy(struct net_device *dev, u32 phyindex) { diff --git a/include/linux/phy_port.h b/include/linux/phy_port.h index 0ef0f5ce4709..4e2a3fdd2f2e 100644 --- a/include/linux/phy_port.h +++ b/include/linux/phy_port.h @@ -36,6 +36,7 @@ struct phy_port_ops { /** * struct phy_port - A representation of a network device physical interfa= ce * + * @id: Unique identifier for the port within the topology * @head: Used by the port's parent to list ports * @parent_type: The type of device this port is directly connected to * @phy: If the parent is PHY_PORT_PHYDEV, the PHY controlling that port @@ -52,6 +53,7 @@ struct phy_port_ops { * @is_sfp: Indicates if this port drives an SFP cage. */ struct phy_port { + u32 id; struct list_head head; enum phy_port_parent parent_type; union { --=20 2.49.0 From nobody Sat Feb 7 12:34:43 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 1BD4A35C1A5; Tue, 27 Jan 2026 13:42:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521352; cv=none; b=B0MXBpohHpflXJNce1NtzF+VFXfnMYbFVNPtdaGirdNsIgiC2djKAy1ITsd51/thRKQwY95CAt7EOxjGt4WCMghAFna9sS7EagpoHaQRVRMa58Tg3TEg1ktdXMCL6lUaVZjy1AzO98dh1qBOoKawI3uXH0zuWeNWec4oXPbUpOs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521352; c=relaxed/simple; bh=g37agUL8FgbZky24zM8Dt6qgHALVVJNhYrx/wBMGpgA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hFt1W2Sr8OsRLHFJnFEp+1ABayTLEMF7DjkSwHdxLZWJxwLhuzHqbtGP/qKH9KsqDwvIN83FBQJEzLID0Q6v9rnjagfbXBnXpvESfAdQFlluIwXQ8g2GSBGG20ezziyo+9YTmVxRirWaSuSoWMgPl97S2eu+3U/nMC2AA3x2Rzw= 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=NYoZyU8+; arc=none smtp.client-ip=185.246.85.4 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="NYoZyU8+" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id BD4174E422D3; Tue, 27 Jan 2026 13:42:29 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 93AF9606F5; Tue, 27 Jan 2026 13:42:29 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 16B73119A8647; Tue, 27 Jan 2026 14:42:26 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769521348; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=Q7in5B95gGhGNfbBBp9uk5VsumQg75Ew576JfetW28U=; b=NYoZyU8+Sm7NBgV8StpL4Swe2SY68AKrlltIS/32QXJ36RKbNH0oPAb40LLFEN2jtXZqA2 NXe10jVK57OCuVmKD8bWCtIGWfYLT7ViDZUQ53DftX0uoC14oyEC3j9swb3wyjW2jw4fKb isqdGI6knzI5MDOuNtA3ZGiwGKpPYbDbbt3RH8zpJ58nzsCAUC25u9aoK4auoEj8aVjKkE oQFLzVxZxXmpz9kQruHoozZGRafo+Y6CNP78+JfRTJNMhmWp1O2vdLnrSaizwrnEeUZcm5 up24zMfBqIRbZ/o5w5RbwV1phi/o1iA5LkXln+EHsyxFrJUjs4YAI6/yFOKHBQ== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , 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, Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next 04/13] net: phylink: Register a phy_port for MAC-driven SFP busses Date: Tue, 27 Jan 2026 14:41:52 +0100 Message-ID: <20260127134202.8208-5-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260127134202.8208-1-maxime.chevallier@bootlin.com> References: <20260127134202.8208-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" phy_port tracks the interfaces that a netdevice feeds into. SFP cages are such ports, but so far we are only tracking the ones that are driven by PHYs acting as media-converters. Let's populate a phy_port for MAC driver SFP cages, handled by phylink. This phy_port represents the SFP cage itself, and not the module that may be plugged into it. It's therefore not an MDI interface, so only the 'interfaces' field is relevant here. The phy_port is only populated for 'NETDEV' phylink instances, as otherwise we don't have any topology to attach the port to. Signed-off-by: Maxime Chevallier --- drivers/net/phy/phylink.c | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 7641f1f41e39..310af33d49a0 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -93,6 +95,7 @@ struct phylink { DECLARE_PHY_INTERFACE_MASK(sfp_interfaces); __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); u8 sfp_port; + struct phy_port *sfp_bus_port; =20 struct eee_config eee_cfg; =20 @@ -1757,6 +1760,46 @@ static void phylink_fixed_poll(struct timer_list *t) =20 static const struct sfp_upstream_ops sfp_phylink_ops; =20 +static int phylink_create_sfp_port(struct phylink *pl) +{ + struct phy_port *port; + int ret =3D 0; + + if (!pl->netdev || !pl->sfp_bus) + return 0; + + port =3D phy_port_alloc(); + if (!port) + return -ENOMEM; + + port->is_sfp =3D true; + port->is_mii =3D true; + port->active =3D true; + + phy_interface_and(port->interfaces, pl->config->supported_interfaces, + phylink_sfp_interfaces); + phy_port_update_supported(port); + + ret =3D phy_link_topo_add_port(pl->netdev, port); + if (ret) + phy_port_destroy(port); + else + pl->sfp_bus_port =3D port; + + return ret; +} + +static void phylink_destroy_sfp_port(struct phylink *pl) +{ + if (pl->netdev && pl->sfp_bus_port) + phy_link_topo_del_port(pl->netdev, pl->sfp_bus_port); + + if (pl->sfp_bus_port) + phy_port_destroy(pl->sfp_bus_port); + + pl->sfp_bus_port =3D NULL; +} + static int phylink_register_sfp(struct phylink *pl, const struct fwnode_handle *fwnode) { @@ -1774,9 +1817,18 @@ static int phylink_register_sfp(struct phylink *pl, =20 pl->sfp_bus =3D bus; =20 + ret =3D phylink_create_sfp_port(pl); + if (ret) { + sfp_bus_put(bus); + return ret; + } + ret =3D sfp_bus_add_upstream(bus, pl, &sfp_phylink_ops); sfp_bus_put(bus); =20 + if (ret) + phylink_destroy_sfp_port(pl); + return ret; } =20 @@ -1938,6 +1990,7 @@ EXPORT_SYMBOL_GPL(phylink_create); void phylink_destroy(struct phylink *pl) { sfp_bus_del_upstream(pl->sfp_bus); + phylink_destroy_sfp_port(pl); if (pl->link_gpio) gpiod_put(pl->link_gpio); =20 --=20 2.49.0 From nobody Sat Feb 7 12:34:43 2026 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 1976535CB67 for ; Tue, 27 Jan 2026 13:42:33 +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=1769521354; cv=none; b=WWSezuWMlNqcCG4tZijb1vfTwpeMIfZwbTdYHsYaR2xEfM9oNbIBfzwqxrZfjAEfp95bnsyKJNu9SMExYSRHa1vKZhAqfHQS6rApVdlUFz7Uyll/UDJVj9WWgq7EDfIveF4S2H+27yybcX5SnDHS40+3eUtGXYjVdrarX1EqgvQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521354; c=relaxed/simple; bh=6tBqceGP+0OrFdNLDH1TqykWaeGTXqOqWs0ohDU5lIs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=o7RV0V4uNOu4R0cfv6baVg/oeiSCgf1tQc9DJfZNyLrXmwZS4Fo5N+0s69P1vE+kyXK9Ig/PZXqoE/LIeDZ2qUA0QVFFHxKvVvsIFDPIbHi74ISqUkxCitz21wGaCG7r/Dfdq4CBWa9+RB59cxgHfMON4y9KWe61Tdih6uHi+EM= 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=p9QOrJy5; 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="p9QOrJy5" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 0B40CC211C2; Tue, 27 Jan 2026 13:42:34 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id E9CC3606F5; Tue, 27 Jan 2026 13:42:31 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id F1563119A864D; Tue, 27 Jan 2026 14:42:28 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769521350; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=amp/VI8/WYNWKbm3uAB6btxp+Kn0n0uAl8u/SSDrfHk=; b=p9QOrJy5i/QK0he1QG7bI/Jz6iBOLu1my9YNChgo2bF4cKbuF9zfBbcOuIFdHePv7kFlCs nTQv6ZgyJaV0REaEF783bV43TPiAGpAYBEWihbAKHdK6SJ9t8ggiI/SlZM0h2NvrOI0ylR AMRvSA/8mdfmaWNPXO3Q5lkjGy/WpJ6l8dsfgrANAM1GdzbMUiyoK6FKi7cgwAiBO2Tx4O MFIFEihCTlv7Z7o++fQrhwnpPIYDMhPnxris4T3diuU2ST0jgey8cQAy6K+ateiCD9Cp9W CiwN8+vgCSrt4gtZCGVTa79uxKeDAcGqUIqr4v+JTypbfvpYv1SY5NwD4Txf7Q== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , 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, Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next 05/13] net: phy: Create SFP phy_port before registering usptream Date: Tue, 27 Jan 2026 14:41:53 +0100 Message-ID: <20260127134202.8208-6-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260127134202.8208-1-maxime.chevallier@bootlin.com> References: <20260127134202.8208-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" When dealing with PHY-driver SFP, we create a phy_port representing the SFP bus when we know we have such a bus. We can move the port creation before registering the sfp upstream ops, as long as we know the SFP bus is there. This will allow passing the phy_port along with the upstream information to the SFP bus. Signed-off-by: Maxime Chevallier --- drivers/net/phy/phy_device.c | 40 +++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 8a3eb1839a3d..819c9e81bdef 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1665,13 +1665,13 @@ static void phy_del_port(struct phy_device *phydev,= struct phy_port *port) phydev->n_ports--; } =20 -static int phy_setup_sfp_port(struct phy_device *phydev) +static struct phy_port *phy_setup_sfp_port(struct phy_device *phydev) { struct phy_port *port =3D phy_port_alloc(); int ret; =20 if (!port) - return -ENOMEM; + return ERR_PTR(-ENOMEM); =20 port->parent_type =3D PHY_PORT_PHY; port->phy =3D phydev; @@ -1686,10 +1686,12 @@ static int phy_setup_sfp_port(struct phy_device *ph= ydev) * when attaching the port to the phydev. */ ret =3D phy_add_port(phydev, port); - if (ret) + if (ret) { phy_port_destroy(port); + return ERR_PTR(ret); + } =20 - return ret; + return port; } =20 /** @@ -1698,22 +1700,32 @@ static int phy_setup_sfp_port(struct phy_device *ph= ydev) */ static int phy_sfp_probe(struct phy_device *phydev) { + struct phy_port *port; struct sfp_bus *bus; - int ret =3D 0; + int ret; + + if (!phydev->mdio.dev.fwnode) + return 0; =20 - if (phydev->mdio.dev.fwnode) { - bus =3D sfp_bus_find_fwnode(phydev->mdio.dev.fwnode); - if (IS_ERR(bus)) - return PTR_ERR(bus); + bus =3D sfp_bus_find_fwnode(phydev->mdio.dev.fwnode); + if (IS_ERR(bus)) + return PTR_ERR(bus); =20 - phydev->sfp_bus =3D bus; + phydev->sfp_bus =3D bus; =20 - ret =3D sfp_bus_add_upstream(bus, phydev, &sfp_phydev_ops); - sfp_bus_put(bus); + if (bus) { + port =3D phy_setup_sfp_port(phydev); + if (IS_ERR(port)) { + sfp_bus_put(bus); + return PTR_ERR(port); + } } =20 - if (!ret && phydev->sfp_bus) - ret =3D phy_setup_sfp_port(phydev); + ret =3D sfp_bus_add_upstream(bus, phydev, &sfp_phydev_ops); + sfp_bus_put(bus); + + if (ret && port) + phy_del_port(phydev, port); =20 return ret; } --=20 2.49.0 From nobody Sat Feb 7 12:34:43 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 9F8EA35C1AF for ; Tue, 27 Jan 2026 13:42:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521357; cv=none; b=sEtBm43rtkaqtYbGx5QuVEO2P1t3WWkISHU8fVbJ2RerIVktLoTrriPp4JFyee0zky9UalXnXQtqUTOoLR4l1jtGbv8u4D+g0vBFCtqK+O26H7UTmL0Xz+fWXWQlcnkB5VUcTPMxwSpwLmccJ+BlwP4CtvcVczgg8mHCUlG93yw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521357; c=relaxed/simple; bh=AxbRNSV+MGlIrdbZNQx3WZxbKnpHL7fzSnW3Fnkk3g4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tDOuP3angEClCw6VH44te84hROIjpHwA+PQsSDWu55qCzAf0riMjelp89fPJjvXVRE2Me28oWpiN1Y3rRJ3y/vcc/h8KL3yaBqA8odk2yw8aQGNc7ZHKLohg6vYDwoeyfbQhfhfE+AcA0ALkvgQuvGklOsJ8cIP2EPwndfLMz7s= 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=pPFfg3wa; arc=none smtp.client-ip=185.246.85.4 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="pPFfg3wa" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 5476A4E422D4; Tue, 27 Jan 2026 13:42:34 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 2A487606F5; Tue, 27 Jan 2026 13:42:34 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 3D785119A8687; Tue, 27 Jan 2026 14:42:31 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769521353; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=8lrGzf6PbbtMSnb6kURa7INkbEyB0GSQ5wN3CCFsZEA=; b=pPFfg3wa6azN6ydEt7rt0orYcnE9rBJszS/eId6K5h3KKdmLdOFsrt6PljzOitrNn8v5y3 wgv6MLRbICCPQCTjAVhDzWcB1jX1NFJgM9YMnOqKvuxd9VdH2O1wxQwlQOP1MdAHYEhqt3 Pe5XZo1JAEeTW9fSLnlDwjNswpiCiiP8H9LTUik8f4E4KGJi8YEth8K4I+0VzWoOMaDORN Vsu7yN6rJVeQNnAu4M8qAetSaq+0j8JT8XrOSEk4rfygSrxNLZT/dyAU/g2PmbyMiKB7Vp 18DeULMwdtT+uBIe2pZu9IpUP7uqAuHwfuSQqZ5Uv8usDobqx3k2cfsUccvbOQ== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , 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, Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next 06/13] net: sfp: Add a sfp-bus ops when connecting a module without PHY Date: Tue, 27 Jan 2026 14:41:54 +0100 Message-ID: <20260127134202.8208-7-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260127134202.8208-1-maxime.chevallier@bootlin.com> References: <20260127134202.8208-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" The SFP bus infrastructure notifies its upstream when a PHY device was discovered on the module. However, we don't have any indication when a module with no PHY was inserted, except for the .insert() and .start() notifications. We want to keep track of the SFP module's capabilities using phy_port. When the module contains an embedded PHY, the PHY driver will expose a phy_port for it. However when there's no PHY, we have no hook to populate the phy_port, so let's introduce one. It is called when we have parsed the module's caps, applied the fixups, tried and failed to probe for a PHY. This will allow the bus' upstream to create the corresponding port, and register it to the topology. Signed-off-by: Maxime Chevallier --- drivers/net/phy/sfp-bus.c | 20 ++++++++++++++++++++ drivers/net/phy/sfp.c | 12 ++++++++++++ drivers/net/phy/sfp.h | 2 ++ include/linux/sfp.h | 5 +++++ 4 files changed, 39 insertions(+) diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c index b945d75966d5..a3d9e28badd0 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c @@ -753,6 +753,26 @@ void sfp_remove_phy(struct sfp_bus *bus) } EXPORT_SYMBOL_GPL(sfp_remove_phy); =20 +int sfp_module_connect_nophy(struct sfp_bus *bus) +{ + const struct sfp_upstream_ops *ops =3D sfp_get_upstream_ops(bus); + + if (ops && ops->connect_nophy) + return ops->connect_nophy(bus->upstream); + + return 0; +} +EXPORT_SYMBOL_GPL(sfp_module_connect_nophy); + +void sfp_module_disconnect_nophy(struct sfp_bus *bus) +{ + const struct sfp_upstream_ops *ops =3D sfp_get_upstream_ops(bus); + + if (ops && ops->disconnect_nophy) + ops->disconnect_nophy(bus->upstream); +} +EXPORT_SYMBOL_GPL(sfp_module_disconnect_nophy); + void sfp_link_up(struct sfp_bus *bus) { const struct sfp_upstream_ops *ops =3D sfp_get_upstream_ops(bus); diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 47f095bd91ce..0f6357a98787 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -1875,6 +1875,8 @@ static void sfp_sm_mod_next(struct sfp *sfp, unsigned= int state, =20 static void sfp_sm_phy_detach(struct sfp *sfp) { + if (!sfp->mod_phy) + sfp_module_disconnect_nophy(sfp->sfp_bus); sfp_remove_phy(sfp->sfp_bus); phy_device_remove(sfp->mod_phy); phy_device_free(sfp->mod_phy); @@ -1918,6 +1920,11 @@ static int sfp_sm_probe_phy(struct sfp *sfp, int add= r, bool is_c45) return 0; } =20 +static int sfp_sm_connect_nophy(struct sfp *sfp) +{ + return sfp_module_connect_nophy(sfp->sfp_bus); +} + static void sfp_sm_link_up(struct sfp *sfp) { sfp_link_up(sfp->sfp_bus); @@ -2749,6 +2756,11 @@ static void sfp_sm_main(struct sfp *sfp, unsigned in= t event) sfp_sm_next(sfp, SFP_S_FAIL, 0); break; } + if (!sfp->mod_phy) { + ret =3D sfp_sm_connect_nophy(sfp); + if (ret) + sfp_sm_next(sfp, SFP_S_FAIL, 0); + } if (sfp_module_start(sfp->sfp_bus)) { sfp_sm_next(sfp, SFP_S_FAIL, 0); break; diff --git a/drivers/net/phy/sfp.h b/drivers/net/phy/sfp.h index 879dff7afe6a..02f3814aac84 100644 --- a/drivers/net/phy/sfp.h +++ b/drivers/net/phy/sfp.h @@ -37,6 +37,8 @@ int sfp_module_insert(struct sfp_bus *bus, const struct s= fp_eeprom_id *id, void sfp_module_remove(struct sfp_bus *bus); int sfp_module_start(struct sfp_bus *bus); void sfp_module_stop(struct sfp_bus *bus); +int sfp_module_connect_nophy(struct sfp_bus *bus); +void sfp_module_disconnect_nophy(struct sfp_bus *bus); struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp, const struct sfp_socket_ops *ops); void sfp_unregister_socket(struct sfp_bus *bus); diff --git a/include/linux/sfp.h b/include/linux/sfp.h index 5c71945a5e4d..20c9f66c1080 100644 --- a/include/linux/sfp.h +++ b/include/linux/sfp.h @@ -561,6 +561,9 @@ struct sfp_module_caps { * on the module. * @disconnect_phy: called when a module with an I2C accessible PHY has * been removed. + * @connect_nophy: called when it was established that the connected module + * doesn't habe an I2C accessible. + * @disconnect_nophy: called when the PHY-less module has been removed. */ struct sfp_upstream_ops { void (*attach)(void *priv, struct sfp_bus *bus); @@ -573,6 +576,8 @@ struct sfp_upstream_ops { void (*link_up)(void *priv); int (*connect_phy)(void *priv, struct phy_device *); void (*disconnect_phy)(void *priv, struct phy_device *); + int (*connect_nophy)(void *priv); + void (*disconnect_nophy)(void *priv); }; =20 #if IS_ENABLED(CONFIG_SFP) --=20 2.49.0 From nobody Sat Feb 7 12:34:43 2026 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 DDE7A35D5E0 for ; Tue, 27 Jan 2026 13:42:37 +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=1769521359; cv=none; b=JDufpkJIhHSRYVuTCZPNOLMgPr1+bgWooASbrP2XI+5j83OmXyxojvXVM2duvDcMViFxcLdQsNLSLWq2aaXri9wz1LFduK4ANXy7ilVX/AlpNJY6gY3GBZr2NwpfgpQDzV26gUNzmZm6nl9IU/8C2Dl9WdAbs3g7WGPnoi8LIaE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521359; c=relaxed/simple; bh=qleloBa2TN5aC4iyE0hKDVge9o/XjTob39QgkrzNH2I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MjNsDn8Z+Q8WjZcvEMfiTF91hXua5Mn+i95K5/0zf9dtHemMgOzGns/CBvvnnynYb1Uv26e8f4XTLdyZsGwtxPUwNJEpPb/aSRrMXiDdwYlDSVZxrZp9ndkqbiQjmC0lbzPwnJtkjW1qe8sQbH1Ri8Rq6y0+vVRWOeRUVuip1DA= 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=rrh5rnRe; 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="rrh5rnRe" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id A7124C211C2; Tue, 27 Jan 2026 13:42:38 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 94B78606F5; Tue, 27 Jan 2026 13:42:36 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 7B5F9119A868D; Tue, 27 Jan 2026 14:42:33 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769521355; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=s68rbjaLhf+OUn2GQuNw8HTQCmS9ib1xVCT46hOJ/6Q=; b=rrh5rnReU5qT7SZNtDRfLjkkZHWyuYI0SK/CUOnpSipSQfwu/GcX0BUgbx4rytICr/XYnD iIakoFOFXQCTIKEURih+w++P7AzuamF1AxfhQFzo2wa5j0akkYzg4R1Y5hG6k3eyQN+f13 9RFK5brc6OxsAJWrnpkBGnxBfM8fStukw79pRFh3J/x9Wy/LdeId6FMzdaoLKkxEzkgMkJ 0uOvvSo8JqwpfOEuAkvuCFKlFcUeWzIXXobvQbZ/UjhufYzFd1kzGL0Hdn5geM7JrWXPIm ZPuUgAY3HfWWD7uPDvfysttxf9NfOoFM2hisb/MznI62rrKab2TV3zmpUKr31Q== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , 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, Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next 07/13] net: phy: Represent PHY-less SFP modules with phy_port Date: Tue, 27 Jan 2026 14:41:55 +0100 Message-ID: <20260127134202.8208-8-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260127134202.8208-1-maxime.chevallier@bootlin.com> References: <20260127134202.8208-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" Now that th SFP bus infrastructure notifies when PHY-less modules are connected, we can create a phy_port to represent it. Instead of letting the SFP subsystem handle that, the Bus' upstream is in charge of maintaining that phy_port and register it to the topology, as the upstream (in this case a phy device) is directly interacting with the underlying net_device. Add a phy_caps helper alongside to get the achievable modes on this module based on what the phy_port representing the bus supports. Signed-off-by: Maxime Chevallier --- drivers/net/phy/phy-caps.h | 2 ++ drivers/net/phy/phy_caps.c | 26 +++++++++++++++ drivers/net/phy/phy_device.c | 62 +++++++++++++++++++++++++++++++++++- include/linux/phy.h | 4 +++ 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/phy-caps.h b/drivers/net/phy/phy-caps.h index 421088e6f6e8..ec3d39a0ae06 100644 --- a/drivers/net/phy/phy-caps.h +++ b/drivers/net/phy/phy-caps.h @@ -66,5 +66,7 @@ void phy_caps_medium_get_supported(unsigned long *support= ed, enum ethtool_link_medium medium, int lanes); u32 phy_caps_mediums_from_linkmodes(unsigned long *linkmodes); +void phy_caps_linkmode_filter_ifaces(unsigned long *to, const unsigned lon= g *from, + const unsigned long *interfaces); =20 #endif /* __PHY_CAPS_H */ diff --git a/drivers/net/phy/phy_caps.c b/drivers/net/phy/phy_caps.c index 942d43191561..558e4df4d63c 100644 --- a/drivers/net/phy/phy_caps.c +++ b/drivers/net/phy/phy_caps.c @@ -445,3 +445,29 @@ u32 phy_caps_mediums_from_linkmodes(unsigned long *lin= kmodes) return mediums; } EXPORT_SYMBOL_GPL(phy_caps_mediums_from_linkmodes); + +/** + * phy_caps_linkmode_filter_ifaces() - Filter linkmodes with an interface = list + * @to: Stores the filtered linkmodes + * @from: Linkmodes to filter + * @interfaces: Bitfield of phy_interface_t that we use for filtering + * + * Filter the provided linkmodes, only to keep the ones we can possibly ac= hieve + * when using any of the provided MII interfaces. + */ +void phy_caps_linkmode_filter_ifaces(unsigned long *to, + const unsigned long *from, + const unsigned long *interfaces) +{ + __ETHTOOL_DECLARE_LINK_MODE_MASK(ifaces_supported) =3D {}; + unsigned int ifaces_caps =3D 0; + phy_interface_t interface; + + for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) + ifaces_caps |=3D phy_caps_from_interface(interface); + + phy_caps_linkmodes(ifaces_caps, ifaces_supported); + + linkmode_and(to, from, ifaces_supported); +} +EXPORT_SYMBOL_GPL(phy_caps_linkmode_filter_ifaces); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 819c9e81bdef..12c8c2ff2c06 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1609,6 +1609,53 @@ static void phy_sfp_link_down(void *upstream) port->ops->link_down(port); } =20 +static int phy_sfp_connect_nophy(void *upstream) +{ + struct phy_device *phydev =3D upstream; + const struct sfp_module_caps *caps; + struct phy_port *port; + int ret =3D 0; + + /* Create mod port */ + port =3D phy_port_alloc(); + if (!port) + return -ENOMEM; + + port->active =3D true; + + caps =3D sfp_get_module_caps(phydev->sfp_bus); + + phy_caps_linkmode_filter_ifaces(port->supported, caps->link_modes, + phydev->sfp_bus_port->interfaces); + + if (phydev->attached_dev) { + ret =3D phy_link_topo_add_port(phydev->attached_dev, port); + if (ret) { + phy_port_destroy(port); + return ret; + } + } + + /* we don't use phy_add_port() here as the module port isn't a direct + * interface from the PHY, but rather an extension to the sfp-bus, that + * is already represented by its own phy_port + */ + phydev->mod_port =3D port; + + return 0; +} + +static void phy_sfp_disconnect_nophy(void *upstream) +{ + struct phy_device *phydev =3D upstream; + + if (phydev->attached_dev) + phy_link_topo_del_port(phydev->attached_dev, phydev->mod_port); + + phy_port_destroy(phydev->mod_port); + phydev->mod_port =3D NULL; +} + static const struct sfp_upstream_ops sfp_phydev_ops =3D { .attach =3D phy_sfp_attach, .detach =3D phy_sfp_detach, @@ -1618,6 +1665,8 @@ static const struct sfp_upstream_ops sfp_phydev_ops = =3D { .link_down =3D phy_sfp_link_down, .connect_phy =3D phy_sfp_connect_phy, .disconnect_phy =3D phy_sfp_disconnect_phy, + .connect_nophy =3D phy_sfp_connect_nophy, + .disconnect_nophy =3D phy_sfp_disconnect_nophy, }; =20 static int phy_add_port(struct phy_device *phydev, struct phy_port *port) @@ -1700,7 +1749,7 @@ static struct phy_port *phy_setup_sfp_port(struct phy= _device *phydev) */ static int phy_sfp_probe(struct phy_device *phydev) { - struct phy_port *port; + struct phy_port *port =3D NULL; struct sfp_bus *bus; int ret; =20 @@ -1727,6 +1776,8 @@ static int phy_sfp_probe(struct phy_device *phydev) if (ret && port) phy_del_port(phydev, port); =20 + phydev->sfp_bus_port =3D port; + return ret; } =20 @@ -1816,6 +1867,12 @@ int phy_attach_direct(struct net_device *dev, struct= phy_device *phydev, err =3D phy_link_topo_add_phy(dev, phydev, PHY_UPSTREAM_MAC, dev); if (err) goto error; + + if (phydev->mod_port) { + err =3D phy_link_topo_add_port(dev, phydev->mod_port); + if (err) + goto error; + } } =20 /* Some Ethernet drivers try to connect to a PHY device before @@ -1989,6 +2046,8 @@ void phy_detach(struct phy_device *phydev) phydev->attached_dev->phydev =3D NULL; phydev->attached_dev =3D NULL; phy_link_topo_del_phy(dev, phydev); + if (phydev->mod_port) + phy_link_topo_del_port(dev, phydev->mod_port); } =20 phydev->phy_link_change =3D NULL; @@ -3816,6 +3875,7 @@ static int phy_remove(struct device *dev) =20 sfp_bus_del_upstream(phydev->sfp_bus); phydev->sfp_bus =3D NULL; + phydev->sfp_bus_port =3D NULL; =20 if (phydev->drv && phydev->drv->remove) phydev->drv->remove(phydev); diff --git a/include/linux/phy.h b/include/linux/phy.h index 6f9979a26892..dc788ae4da64 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -594,6 +594,8 @@ struct phy_oatc14_sqi_capability { * @phylink: Pointer to phylink instance for this PHY * @sfp_bus_attached: Flag indicating whether the SFP bus has been attached * @sfp_bus: SFP bus attached to this PHY's fiber port + * @sfp_bus_port: The phy_port connected to the downstream SFP bus + * @mod_port: phy_port representing the SFP module, if it is phy-less * @attached_dev: The attached enet driver's device instance ptr * @adjust_link: Callback for the enet controller to respond to changes: i= n the * link state. @@ -782,6 +784,8 @@ struct phy_device { /* This may be modified under the rtnl lock */ bool sfp_bus_attached; struct sfp_bus *sfp_bus; + struct phy_port *sfp_bus_port; + struct phy_port *mod_port; struct phylink *phylink; struct net_device *attached_dev; struct mii_timestamper *mii_ts; --=20 2.49.0 From nobody Sat Feb 7 12:34:43 2026 Received: from smtpout-02.galae.net (smtpout-02.galae.net [185.246.84.56]) (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 6EF6535D604 for ; Tue, 27 Jan 2026 13:42:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.84.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521361; cv=none; b=N9z2KyQeayBXMrKH8tbEzbegEpC1E4H1MlDII6D2ZDDYCFitSdPPdleih5WmtmlwEr7dzgH1+tBnY3B2lyIV9f8fH31NKy0pQjF1e1QZkga19BdHul/MvK23UucDjgPzGb3rRUAT4WTDwcSBBkyuDYaj1Ho0SH8t8b9/vxHAEpM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521361; c=relaxed/simple; bh=TQJLvfrLbkpH2tgRH3T5MjUllU/MA6zjpa35N8wYB34=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Z45VPzFgIHoSoNOk3kwjzJbYeCcnUSHvCs9xvKRe0/RbtzG1nCe08IWTkjtYSby1MQXf8i2hJdL2iihUhtkJWhxyqsCD1bjfIsdm40fHVAZ+0eOwBZjX55AnrQjCIQLJYyLbpzeUpGsk+tMFNY9+7rEf1es50l5kWW9WM+B4utg= 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=GPopLQC6; arc=none smtp.client-ip=185.246.84.56 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="GPopLQC6" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id 0B72C1A2A82; Tue, 27 Jan 2026 13:42:39 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id D62FC606F5; Tue, 27 Jan 2026 13:42:38 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id ECA88119A8690; Tue, 27 Jan 2026 14:42:35 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769521357; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=bqj8JUK2+OuAF2zK25RJrBtPlN18kp54KfaV+cibShA=; b=GPopLQC6LSNgHlCia3rwWxec0uztQlGP+UuCOMvVpCOdkw9sGVYn/i207piacN4zQmfxCQ 6A+/+8N57XOMqaboDH4UWokjmuI6OKha7oSmd/EhnKzPUmjUxx4WKussaS/2oMlXkOJlyb CSyPZ/YV/gsMUj9TFFvyf/6ZMRkwUvTrQ1Mw0299YgoL8UILWefrO2DIos1KwesZFzpceq mkD0ePs0k3hZ2RTdStmXwMvHfaXbOimzV19yTm2LEduYBnPbwHh/qzSlNK52TCy6pDR6M1 VV850IdpcOaNqdJwMlHaEbyEhJ2RDv1yGGzjBCeC/GoWVCu3UuHE6MjnvHMM2A== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , 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, Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next 08/13] net: phylink: Represent PHY-less SFP modules with phy_port Date: Tue, 27 Jan 2026 14:41:56 +0100 Message-ID: <20260127134202.8208-9-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260127134202.8208-1-maxime.chevallier@bootlin.com> References: <20260127134202.8208-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" Let phylink handle the phy_port for PHY-less modules, and register it to the topology. Signed-off-by: Maxime Chevallier --- drivers/net/phy/phylink.c | 68 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 310af33d49a0..6c62604b00a6 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -96,6 +96,7 @@ struct phylink { __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); u8 sfp_port; struct phy_port *sfp_bus_port; + struct phy_port *mod_port; =20 struct eee_config eee_cfg; =20 @@ -1786,13 +1787,31 @@ static int phylink_create_sfp_port(struct phylink *= pl) else pl->sfp_bus_port =3D port; =20 + if (pl->mod_port) { + ret =3D phy_link_topo_add_port(pl->netdev, pl->mod_port); + if (ret) + goto out_bus_port; + } + + return 0; +out_bus_port: + phy_link_topo_del_port(pl->netdev, port); + phy_port_destroy(port); return ret; } =20 static void phylink_destroy_sfp_port(struct phylink *pl) { - if (pl->netdev && pl->sfp_bus_port) - phy_link_topo_del_port(pl->netdev, pl->sfp_bus_port); + if (pl->netdev) { + if (pl->sfp_bus_port) + phy_link_topo_del_port(pl->netdev, pl->sfp_bus_port); + + /* Only remove it from the topology, it will be destroyed at + * module removal. + */ + if (pl->mod_port) + phy_link_topo_del_port(pl->netdev, pl->mod_port); + } =20 if (pl->sfp_bus_port) phy_port_destroy(pl->sfp_bus_port); @@ -3998,6 +4017,49 @@ static void phylink_sfp_disconnect_phy(void *upstrea= m, phylink_disconnect_phy(upstream); } =20 +static int phylink_sfp_connect_nophy(void *upstream) +{ + const struct sfp_module_caps *caps; + struct phylink *pl =3D upstream; + struct phy_port *port; + int ret =3D 0; + + /* Create mod port */ + port =3D phy_port_alloc(); + if (!port) + return -ENOMEM; + + port->active =3D true; + + caps =3D sfp_get_module_caps(pl->sfp_bus); + + phy_caps_linkmode_filter_ifaces(port->supported, caps->link_modes, + pl->sfp_bus_port->interfaces); + + if (pl->netdev) { + ret =3D phy_link_topo_add_port(pl->netdev, port); + if (ret) { + phy_port_destroy(port); + return ret; + } + } + + pl->mod_port =3D port; + + return 0; +} + +static void phylink_sfp_disconnect_nophy(void *upstream) +{ + struct phylink *pl =3D upstream; + + if (pl->netdev) + phy_link_topo_del_port(pl->netdev, pl->mod_port); + + phy_port_destroy(pl->mod_port); + pl->mod_port =3D NULL; +} + static const struct sfp_upstream_ops sfp_phylink_ops =3D { .attach =3D phylink_sfp_attach, .detach =3D phylink_sfp_detach, @@ -4009,6 +4071,8 @@ static const struct sfp_upstream_ops sfp_phylink_ops = =3D { .link_down =3D phylink_sfp_link_down, .connect_phy =3D phylink_sfp_connect_phy, .disconnect_phy =3D phylink_sfp_disconnect_phy, + .connect_nophy =3D phylink_sfp_connect_nophy, + .disconnect_nophy =3D phylink_sfp_disconnect_nophy, }; =20 /* Helpers for MAC drivers */ --=20 2.49.0 From nobody Sat Feb 7 12:34:43 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 B957035DCF2; Tue, 27 Jan 2026 13:42:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521364; cv=none; b=qSQdSpiPfO7BnozVJOy9VYzl9DNX+DF3WX2lQKKBBO6/kdRI71RA6HtVnQM6TKPw2W0e2UasHwV9Eos946eR4ROvUeKCk/rYEuzqjjX6PyrwWCd9FQT5llpY5K8rVjUdQTu72IH00n7Fi8BJlBsDziXD0alaraxGTsmAcle0oBI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521364; c=relaxed/simple; bh=1C2dhFrK8v121Gqqc49xuuHTTbn/EOQWNDC6jq6YQnI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NidcBCahRpxUYssHkZr3M8c+VKBy+QQdPzRkPKQKZnGDaEQijzk9Pn53DpP9So4wPaOd3xGKqM2dU3qfb0/LM2ooWeB/otefTv7TRS7DuHnf+vbKCidaqWXekhz/PwEUZH3Ib+ZwK13EnKIqKcJODwBXiMj4gW5/Dw8umBd90Lg= 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=oZb9ASBB; arc=none smtp.client-ip=185.246.85.4 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="oZb9ASBB" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 76C7F4E422D5; Tue, 27 Jan 2026 13:42:41 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 4D56D606F5; Tue, 27 Jan 2026 13:42:41 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 4AC3F119A8692; Tue, 27 Jan 2026 14:42:38 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769521360; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=KQcmnl8gxMjsz0wTL/rmjX7tdjhBz25xY9Z+8rYR0kY=; b=oZb9ASBBBlMpAVO8NGNMZF2weCqVwXBV0Mf+m9ExFB9gDheajxH4uWMjQwHHcNgQGYvpQf DDnRSeu5cQQ7rvZPTy5izjxfrUXQ3XN0l8fJsdahzij85GHnXkqKZOXnBruKpyjtyrGHcp AU+4tABsZEklM5a6f7oRa3gVtowFVxmQvDUYpMtTgBmOAVIP1j1bsamwzp1pYc1QIwkQmc C+uNDV/AInW0/BI/WrHS3XKzkvJ6CIxeXubgTwpsC9SsYX18aFA1H+C9G0GCEnfPhRIvQ6 yepIZhrjORFACdyjRLQfYVCA4WfMk6ninLNT5Ru6+wU5P6ugtc488PYhutbvlQ== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , 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, Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next 09/13] net: phy: phy_port: Store information about a MII port's occupancy Date: Tue, 27 Jan 2026 14:41:57 +0100 Message-ID: <20260127134202.8208-10-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260127134202.8208-1-maxime.chevallier@bootlin.com> References: <20260127134202.8208-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" MII phy_ports are not meant to be connected directly to a link partner. They are meant to feed into some media converter devices, so far we only support SFP modules for that. We have information about what MII they can handle, however we don't store anything about whether they are currently connected to an SFP module or not. As phy_port aims at listing the front-facing ports, let's store an "occupied" bit to know whether or not a MII port is currently front-facing (i.e. there's no module in the SFP cage), or occupied (i.e. there's an SFP module). Signed-off-by: Maxime Chevallier --- drivers/net/phy/phy_device.c | 4 ++++ drivers/net/phy/phylink.c | 4 ++++ include/linux/phy_port.h | 3 +++ 3 files changed, 11 insertions(+) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 12c8c2ff2c06..1dba5f06124f 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1636,6 +1636,8 @@ static int phy_sfp_connect_nophy(void *upstream) } } =20 + phydev->sfp_bus_port->occupied =3D true; + /* we don't use phy_add_port() here as the module port isn't a direct * interface from the PHY, but rather an extension to the sfp-bus, that * is already represented by its own phy_port @@ -1649,6 +1651,8 @@ static void phy_sfp_disconnect_nophy(void *upstream) { struct phy_device *phydev =3D upstream; =20 + phydev->sfp_bus_port->occupied =3D false; + if (phydev->attached_dev) phy_link_topo_del_port(phydev->attached_dev, phydev->mod_port); =20 diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 6c62604b00a6..3f76b1bbb627 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -4044,6 +4044,8 @@ static int phylink_sfp_connect_nophy(void *upstream) } } =20 + pl->sfp_bus_port->occupied =3D true; + pl->mod_port =3D port; =20 return 0; @@ -4053,6 +4055,8 @@ static void phylink_sfp_disconnect_nophy(void *upstre= am) { struct phylink *pl =3D upstream; =20 + pl->sfp_bus_port->occupied =3D false; + if (pl->netdev) phy_link_topo_del_port(pl->netdev, pl->mod_port); =20 diff --git a/include/linux/phy_port.h b/include/linux/phy_port.h index 4e2a3fdd2f2e..8d4f20bfd9dd 100644 --- a/include/linux/phy_port.h +++ b/include/linux/phy_port.h @@ -51,6 +51,8 @@ struct phy_port_ops { * @is_mii: Indicates if this port is MII (Media Independent Interface), * or MDI (Media Dependent Interface). * @is_sfp: Indicates if this port drives an SFP cage. + * @occupied: Indicates if this port feeds into an another component that = has + * a front-facing interface. */ struct phy_port { u32 id; @@ -71,6 +73,7 @@ struct phy_port { unsigned int active:1; unsigned int is_mii:1; unsigned int is_sfp:1; + unsigned int occupied:1; }; =20 struct phy_port *phy_port_alloc(void); --=20 2.49.0 From nobody Sat Feb 7 12:34:43 2026 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 2898035DD1E; Tue, 27 Jan 2026 13:42:45 +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=1769521366; cv=none; b=CEWZnV9FqIlKjrdNx3Pbf/+PtFIK5bN2822U4Rp+k7bU8llcxHFmhvBzfYcnhRo0pBCmn8dlnFQlMxx5JCUrFEPmOobhlhtH/LpnIFKnGxuwTaEKQGh9GHMba/S2m0cfhEWuB/jky0SveuZzjlGLZBOs3+/rN0OQ7hPBIsmulsU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521366; c=relaxed/simple; bh=1JTSbK0lXDa0qB/bu/313wVupHvb21M0el6GgWLuhnU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lxTkEJk3DJF3Ji/i4M6IdEvd63zB2K/M5WMZXqye+kj4uslc1jaV4wvpGjpJJEoa6nkwTw5xhhGmzb+P7juuw4vxIqiak3dDnPypR3f5lr2hYchZX6r3S68RkWjZ9zZrph1Fl3ZcoUlbFiEZe0U6ekwhk+oMkV1+4idBlJBRYVM= 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=ArI5rSTL; 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="ArI5rSTL" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id E4614C211C0; Tue, 27 Jan 2026 13:42:45 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id D2332606F5; Tue, 27 Jan 2026 13:42:43 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id A262E119A8693; Tue, 27 Jan 2026 14:42:40 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769521362; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=LQ1Qarsz5LhrrgmIa0E4ThARGgHfTWIRhhaAwOPHPVc=; b=ArI5rSTL8u1CXuhSFn1Vc+bblrnAn5ZdQ81oJKOWrg2FkBxjQOH5n6VDS1vcU7EtecscE6 sb1jfafFofxPyTSb4fPV010sLE17XmrXyymfIrIvwrCJM+5Q2yyif9DJGZBOQK0cNTvOoa 316Rv7FCIJVyFZp349jUXT7KyexRzSWVBMWRoloj5mst96Eun/zgCNhyOmBXpHHwXNFrnP op4nMmdjMFoe72jumafSTAFGhcyCgDa+59kbzA5si8g6g20FzowEZovMykOeMdxvSGHSOd PE2J6O8ceyiszelx55QiAgNj7E9yRyXhpoBqWCqKPkBCJ7yJcBoHnDnS3uNgyw== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , 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, Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports Date: Tue, 27 Jan 2026 14:41:58 +0100 Message-ID: <20260127134202.8208-11-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260127134202.8208-1-maxime.chevallier@bootlin.com> References: <20260127134202.8208-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" In order to allow netlink access to phy_ports, let's add a helper to retrieve them. When handling a port coming from phy_link_topology, the caller must hold rtnl until it's done with it. Signed-off-by: Maxime Chevallier --- include/linux/phy_link_topology.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/linux/phy_link_topology.h b/include/linux/phy_link_top= ology.h index 66bceff72b19..d5f8f20c5d32 100644 --- a/include/linux/phy_link_topology.h +++ b/include/linux/phy_link_topology.h @@ -66,6 +66,17 @@ phy_link_topo_get_phy(struct net_device *dev, u32 phyind= ex) return NULL; } =20 +static inline struct phy_port * +phy_link_topo_get_port(struct net_device *dev, u32 port_id) +{ + struct phy_link_topology *topo =3D dev->link_topo; + + if (!topo) + return NULL; + + return xa_load(&topo->ports, port_id); +} + #else static inline int phy_link_topo_add_phy(struct net_device *dev, struct phy_device *phy, @@ -95,6 +106,11 @@ phy_link_topo_get_phy(struct net_device *dev, u32 phyin= dex) { return NULL; } + +phy_link_topo_get_port(struct net_device *dev, u32 port_id) +{ + return NULL; +} #endif =20 #endif /* __PHY_LINK_TOPOLOGY_H */ --=20 2.49.0 From nobody Sat Feb 7 12:34:43 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 D8C9235E55F; Tue, 27 Jan 2026 13:42:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521369; cv=none; b=dNQSHnVYrQGwMTxq9fpDnnqmpaKD6wlSpoG9r6dETfPI1I8pJ8yYf8+SB02aa9wWoEGlva8fltwIyGdkcqJSbz8SEVeLL/Qsslqyn40tqBavNCnV+bboSJ5db9eexjTMnC7WMD8Wn6vvzPAuvKx9QC/N6KWrxQuBH++7PcAv+9o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521369; c=relaxed/simple; bh=eaH4DCg8PG4Qegz0pzNo2jDRbz5YV59l7hffXKKyWVw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cSIp354Z/AsEgoT0zIeZNu8QFVCyL7LOviyYoA5OV2Yi10H1jAnkLw3hrEFD43HeWsbfvsMKRWn0r7I2wd/kFw96q6Qmtmc7NXjATwWYAqmOG6R69VEXt0R+9t0iU6+0+ET+mJCVCllz1+YMasoyu6q8X3zQANkUikhm94yCz3U= 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=YBc3+5Ug; arc=none smtp.client-ip=185.246.85.4 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="YBc3+5Ug" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 9A4A14E422D2; Tue, 27 Jan 2026 13:42:46 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 6CAA9606F5; Tue, 27 Jan 2026 13:42:46 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 07AB0119A8695; Tue, 27 Jan 2026 14:42:42 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769521365; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=H9jO5cGzIFudrj2fBUC0gHtKPdipIN1zDR03sFJ/icQ=; b=YBc3+5UgxfAtJlCe0ul8djtlz0fzu18HWByJcAncmqIZ8hzk6Nt+PzFIq3q8unte4P2/LP KZHnwuvug7j4HpsU5Norfgr1SP/a4wpF9Aem2Wj6NCcvTXkuWrN3xFToujZ6Hh1NFBliN9 2M++ojZcRl3z7iKTTHcQV3pa5J3uPqXEfHNC0z7KAZl76OvFxTCBx2U0wIBQVVpNSCfOfF 4L+RKOsxILumhdtyDZQUvQbWL0e6T8C75+KSe8j7EZtWfEx2z0On08xaarpmp8xBajGGgJ nLRoB/W0busmPJXgdIwfAj7ZEdI+qhMJx3JPtWB24/MHB5PVjsJcDr3yK92/1Q== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , 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, Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next 11/13] net: phy: store phy_modes in a static array Date: Tue, 27 Jan 2026 14:41:59 +0100 Message-ID: <20260127134202.8208-12-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260127134202.8208-1-maxime.chevallier@bootlin.com> References: <20260127134202.8208-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" The phy_modes() helper provided by include/linux/phy.h returns the name of a phy_interface_t value. As it may be used by callers that don't depend on PHYLIB, it's a static inline function. We want to report using netlink the phy_interface_t types that may be accessible on a phy_port, especially for SFP cages. We need access to that array of phy_interface_t names, let's therefore store it into a dedicated array in net/ethtool/common.c. This is part of CONFIG_NET, so it's accessible even without dependency on PHYLIB. Signed-off-by: Maxime Chevallier --- include/linux/phy.h | 84 +++----------------------------------------- net/ethtool/common.c | 44 +++++++++++++++++++++++ 2 files changed, 49 insertions(+), 79 deletions(-) diff --git a/include/linux/phy.h b/include/linux/phy.h index dc788ae4da64..cf607c1a5127 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -199,6 +199,8 @@ static inline void phy_interface_set_rgmii(unsigned lon= g *intf) __set_bit(PHY_INTERFACE_MODE_RGMII_TXID, intf); } =20 +extern const char phy_interface_names[][ETH_GSTRING_LEN]; + /** * phy_modes - map phy_interface_t enum to device tree binding of phy-mode * @interface: enum phy_interface_t value @@ -209,86 +211,10 @@ static inline void phy_interface_set_rgmii(unsigned l= ong *intf) */ static inline const char *phy_modes(phy_interface_t interface) { - switch (interface) { - case PHY_INTERFACE_MODE_NA: - return ""; - case PHY_INTERFACE_MODE_INTERNAL: - return "internal"; - case PHY_INTERFACE_MODE_MII: - return "mii"; - case PHY_INTERFACE_MODE_GMII: - return "gmii"; - case PHY_INTERFACE_MODE_SGMII: - return "sgmii"; - case PHY_INTERFACE_MODE_TBI: - return "tbi"; - case PHY_INTERFACE_MODE_REVMII: - return "rev-mii"; - case PHY_INTERFACE_MODE_RMII: - return "rmii"; - case PHY_INTERFACE_MODE_REVRMII: - return "rev-rmii"; - case PHY_INTERFACE_MODE_RGMII: - return "rgmii"; - case PHY_INTERFACE_MODE_RGMII_ID: - return "rgmii-id"; - case PHY_INTERFACE_MODE_RGMII_RXID: - return "rgmii-rxid"; - case PHY_INTERFACE_MODE_RGMII_TXID: - return "rgmii-txid"; - case PHY_INTERFACE_MODE_RTBI: - return "rtbi"; - case PHY_INTERFACE_MODE_SMII: - return "smii"; - case PHY_INTERFACE_MODE_XGMII: - return "xgmii"; - case PHY_INTERFACE_MODE_XLGMII: - return "xlgmii"; - case PHY_INTERFACE_MODE_MOCA: - return "moca"; - case PHY_INTERFACE_MODE_PSGMII: - return "psgmii"; - case PHY_INTERFACE_MODE_QSGMII: - return "qsgmii"; - case PHY_INTERFACE_MODE_TRGMII: - return "trgmii"; - case PHY_INTERFACE_MODE_1000BASEX: - return "1000base-x"; - case PHY_INTERFACE_MODE_1000BASEKX: - return "1000base-kx"; - case PHY_INTERFACE_MODE_2500BASEX: - return "2500base-x"; - case PHY_INTERFACE_MODE_5GBASER: - return "5gbase-r"; - case PHY_INTERFACE_MODE_RXAUI: - return "rxaui"; - case PHY_INTERFACE_MODE_XAUI: - return "xaui"; - case PHY_INTERFACE_MODE_10GBASER: - return "10gbase-r"; - case PHY_INTERFACE_MODE_25GBASER: - return "25gbase-r"; - case PHY_INTERFACE_MODE_USXGMII: - return "usxgmii"; - case PHY_INTERFACE_MODE_10GKR: - return "10gbase-kr"; - case PHY_INTERFACE_MODE_100BASEX: - return "100base-x"; - case PHY_INTERFACE_MODE_QUSGMII: - return "qusgmii"; - case PHY_INTERFACE_MODE_10G_QXGMII: - return "10g-qxgmii"; - case PHY_INTERFACE_MODE_50GBASER: - return "50gbase-r"; - case PHY_INTERFACE_MODE_LAUI: - return "laui"; - case PHY_INTERFACE_MODE_100GBASEP: - return "100gbase-p"; - case PHY_INTERFACE_MODE_MIILITE: - return "mii-lite"; - default: + if (interface > PHY_INTERFACE_MODE_MAX) return "unknown"; - } + + return phy_interface_names[interface]; } =20 /** diff --git a/net/ethtool/common.c b/net/ethtool/common.c index 4036561b078b..d795d9a8b0cd 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -483,6 +483,50 @@ static const char ethtool_link_medium_names[][ETH_GSTR= ING_LEN] =3D { }; static_assert(ARRAY_SIZE(ethtool_link_medium_names) =3D=3D __ETHTOOL_LINK_= MEDIUM_LAST); =20 +const char phy_interface_names[][ETH_GSTRING_LEN] =3D { + [PHY_INTERFACE_MODE_NA] =3D "", + [PHY_INTERFACE_MODE_INTERNAL] =3D "internal", + [PHY_INTERFACE_MODE_MII] =3D "mii", + [PHY_INTERFACE_MODE_GMII] =3D "gmii", + [PHY_INTERFACE_MODE_SGMII] =3D "sgmii", + [PHY_INTERFACE_MODE_TBI] =3D "tbi", + [PHY_INTERFACE_MODE_REVMII] =3D "rev-mii", + [PHY_INTERFACE_MODE_RMII] =3D "rmii", + [PHY_INTERFACE_MODE_REVRMII] =3D "rev-rmii", + [PHY_INTERFACE_MODE_RGMII] =3D "rgmii", + [PHY_INTERFACE_MODE_RGMII_ID] =3D "rgmii-id", + [PHY_INTERFACE_MODE_RGMII_RXID] =3D "rgmii-rxid", + [PHY_INTERFACE_MODE_RGMII_TXID] =3D "rgmii-txid", + [PHY_INTERFACE_MODE_RTBI] =3D "rtbi", + [PHY_INTERFACE_MODE_SMII] =3D "smii", + [PHY_INTERFACE_MODE_XGMII] =3D "xgmii", + [PHY_INTERFACE_MODE_XLGMII] =3D "xlgmii", + [PHY_INTERFACE_MODE_MOCA] =3D "moca", + [PHY_INTERFACE_MODE_PSGMII] =3D "psgmii", + [PHY_INTERFACE_MODE_QSGMII] =3D "qsgmii", + [PHY_INTERFACE_MODE_TRGMII] =3D "trgmii", + [PHY_INTERFACE_MODE_1000BASEX] =3D "1000base-x", + [PHY_INTERFACE_MODE_1000BASEKX] =3D "1000base-kx", + [PHY_INTERFACE_MODE_2500BASEX] =3D "2500base-x", + [PHY_INTERFACE_MODE_5GBASER] =3D "5gbase-r", + [PHY_INTERFACE_MODE_RXAUI] =3D "rxaui", + [PHY_INTERFACE_MODE_XAUI] =3D "xaui", + [PHY_INTERFACE_MODE_10GBASER] =3D "10gbase-r", + [PHY_INTERFACE_MODE_25GBASER] =3D "25gbase-r", + [PHY_INTERFACE_MODE_USXGMII] =3D "usxgmii", + [PHY_INTERFACE_MODE_10GKR] =3D "10gbase-kr", + [PHY_INTERFACE_MODE_100BASEX] =3D "100base-x", + [PHY_INTERFACE_MODE_QUSGMII] =3D "qusgmii", + [PHY_INTERFACE_MODE_10G_QXGMII] =3D "10g-qxgmii", + [PHY_INTERFACE_MODE_50GBASER] =3D "50gbase-r", + [PHY_INTERFACE_MODE_LAUI] =3D "laui", + [PHY_INTERFACE_MODE_100GBASEP] =3D "100gbase-p", + [PHY_INTERFACE_MODE_MIILITE] =3D "mii-lite", + +}; +static_assert(ARRAY_SIZE(phy_interface_names) =3D=3D PHY_INTERFACE_MODE_MA= X); +EXPORT_SYMBOL_GPL(phy_interface_names); + const char netif_msg_class_names[][ETH_GSTRING_LEN] =3D { [NETIF_MSG_DRV_BIT] =3D "drv", [NETIF_MSG_PROBE_BIT] =3D "probe", --=20 2.49.0 From nobody Sat Feb 7 12:34:43 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 5EE1F35EDBE for ; Tue, 27 Jan 2026 13:42:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521371; cv=none; b=hjSBFD463FsN769d+XpoSd1iAhcm4DE03cGd3YDRAhNdRsCyz5tz2lIy4uOfPn4CkIh9s8BBlH5BxdukL1LbJaxVXUsC3xq+SEiy3EfWDi2s4G7ekeby1OufU24inD0Nj3SwGYsMwHhnCrQkn2afI6g1X04QOBWcUj7tFv05vpU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521371; c=relaxed/simple; bh=dIW9DmuRZ6tKWsiS7mSRMUwkt75gVBWc0F9T4GKBWXA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=t1Xw8aJcTuL1ZTbXpAvKR05bhfXLjmcZOw0QT8pEdvDW1+y4X6UmwjwoKF4j/VgWi+UtRMtanZU5Ae8pUxRP7Xiepppn+FmpRMYfosd9+1z1bSGLTPWG5fuhj/vuM+c4yHXS+lQ1zEMgeO0OqgBS+bIXuW1DdkQgTpzxs8anSR0= 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=QFgv3IBR; arc=none smtp.client-ip=185.246.85.4 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="QFgv3IBR" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 13CD64E422D3; Tue, 27 Jan 2026 13:42:49 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id DC03B606F5; Tue, 27 Jan 2026 13:42:48 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 7971F119A8647; Tue, 27 Jan 2026 14:42:45 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769521367; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=JE1ajPZV3RBLMmNHm3FO3KqAiha9kx7cpVHokUOQiNc=; b=QFgv3IBR6MRr+C4KXQbQZIogintzCljAemoiXBDCIzOurWAzlnU+RQBeMNYVARGhEHvCGP G17QkATcyvP/pkbseAvcJ19VEUhfrTmAZO8+G1WwjwvZM0XhgjjYxDnP/hX4z2pK2s6WdG Gxox07/cc92+8cvAqSXTtYti4JLg2Y2cI28lwlO462+07wIsJ8YnJtLXEQzYpm1HdmDYLn GN0C7wT3nVm9ma2RSE9MwQWSwEuTF1HFmBwrzxmFu/vihzjxKcwjHbsELtn82wy76HqBwR A4WCd71MjPQLQWUrFzeRCo06BktvzaR+4DlyH35XeJ0Doko8bPTwnkjcmPDRGw== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , 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, Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next 12/13] netlink: specs: Add ethernet port listing with ethtool Date: Tue, 27 Jan 2026 14:42:00 +0100 Message-ID: <20260127134202.8208-13-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260127134202.8208-1-maxime.chevallier@bootlin.com> References: <20260127134202.8208-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" Ethernet network interfaces may have more than one front-facing port. The phy_port infrastructure was introduced to keep track of these ports, and allow userspace to know about the presence and capability of these ports. Add a ethnl netlink message to report this information. Signed-off-by: Maxime Chevallier --- Documentation/netlink/specs/ethtool.yaml | 50 +++++++++++++++++++ Documentation/networking/ethtool-netlink.rst | 35 +++++++++++++ .../uapi/linux/ethtool_netlink_generated.h | 19 +++++++ 3 files changed, 104 insertions(+) diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netli= nk/specs/ethtool.yaml index 0a2d2343f79a..f0f424009fb0 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -210,6 +210,10 @@ definitions: - name: discard value: 31 + - + name: port-type + type: enum + entries: [mdi, sfp] =20 attribute-sets: - @@ -1890,6 +1894,32 @@ attribute-sets: name: link type: nest nested-attributes: mse-snapshot + - + name: port + attr-cnt-name: --ethtool-a-port-cnt + attributes: + - + name: header + type: nest + nested-attributes: header + - + name: id + type: u32 + - + name: supported-modes + type: nest + nested-attributes: bitset + - + name: supported-interfaces + type: nest + nested-attributes: bitset + - + name: type + type: u8 + enum: port-type + - + name: occupied + type: u8 =20 operations: enum-model: directional @@ -2842,6 +2872,26 @@ operations: - worst-channel - link dump: *mse-get-op + - + name: port-get + doc: Get ports attached to an interface + + attribute-set: port + + do: &port-get-op + request: + attributes: + - header + - id + reply: + attributes: + - header + - id + - supported-modes + - supported-interfaces + - type + - occupied + dump: *port-get-op =20 mcast-groups: list: diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/n= etworking/ethtool-netlink.rst index af56c304cef4..450004d545b8 100644 --- a/Documentation/networking/ethtool-netlink.rst +++ b/Documentation/networking/ethtool-netlink.rst @@ -2522,6 +2522,40 @@ Within each channel nest, only the metrics supported= by the PHY will be present. See ``struct phy_mse_snapshot`` kernel documentation in ``include/linux/phy.h``. =20 +PORT_GET +=3D=3D=3D=3D=3D=3D=3D=3D + +Retrieve information about the physical connection points of a network dev= ice, +referred to as "ports". User needs to specify a PORT_ID for the DO operati= on, +in which case the DO request returns information about that specific port. + +As there can be more than one port, the DUMP operation can be used to list= the +ports present on a given interface, by passing an interface index or name = in +the dump request. + +Request contents: + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + ``ETHTOOL_A_PORT_HEADER`` nested request header + ``ETHTOOL_A_PORT_ID`` u32 port id + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D + +Kernel response contents: + + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + ``ETHTOOL_A_PORT_HEADER`` nested request header + ``ETHTOOL_A_PORT_ID`` u32 the port's unique identi= fier, + per netdevice. + ``ETHTOOL_A_PORT_SUPPORTED_MODES`` bitset bitset of supported link= modes + ``ETHTOOL_A_PORT_SUPPORTED_INTERFACES`` bitset bitset of supported MII + interfaces + ``ETHTOOL_A_PORT_TYPE`` u32 the port type + ``ETHTOOL_A_PORT_OCCUPIED`` u8 for non-mdi ports, indic= ates + if the port is connected + another device that could + expose a MDI + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + Request translation =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 @@ -2632,4 +2666,5 @@ are netlink only. n/a ``ETHTOOL_MSG_PHY_GET`` ``SIOCGHWTSTAMP`` ``ETHTOOL_MSG_TSCONFIG_GET`` ``SIOCSHWTSTAMP`` ``ETHTOOL_MSG_TSCONFIG_SET`` + n/a ``ETHTOOL_MSG_PORT_GET`` =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D diff --git a/include/uapi/linux/ethtool_netlink_generated.h b/include/uapi/= linux/ethtool_netlink_generated.h index 556a0c834df5..7ccd864a6e38 100644 --- a/include/uapi/linux/ethtool_netlink_generated.h +++ b/include/uapi/linux/ethtool_netlink_generated.h @@ -78,6 +78,11 @@ enum ethtool_pse_event { ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR =3D 64, }; =20 +enum ethtool_port_type { + ETHTOOL_PORT_TYPE_MDI, + ETHTOOL_PORT_TYPE_SFP, +}; + enum { ETHTOOL_A_HEADER_UNSPEC, ETHTOOL_A_HEADER_DEV_INDEX, @@ -837,6 +842,18 @@ enum { ETHTOOL_A_MSE_MAX =3D (__ETHTOOL_A_MSE_CNT - 1) }; =20 +enum { + ETHTOOL_A_PORT_HEADER =3D 1, + ETHTOOL_A_PORT_ID, + ETHTOOL_A_PORT_SUPPORTED_MODES, + ETHTOOL_A_PORT_SUPPORTED_INTERFACES, + ETHTOOL_A_PORT_TYPE, + ETHTOOL_A_PORT_OCCUPIED, + + __ETHTOOL_A_PORT_CNT, + ETHTOOL_A_PORT_MAX =3D (__ETHTOOL_A_PORT_CNT - 1) +}; + enum { ETHTOOL_MSG_USER_NONE =3D 0, ETHTOOL_MSG_STRSET_GET =3D 1, @@ -890,6 +907,7 @@ enum { ETHTOOL_MSG_RSS_CREATE_ACT, ETHTOOL_MSG_RSS_DELETE_ACT, ETHTOOL_MSG_MSE_GET, + ETHTOOL_MSG_PORT_GET, =20 __ETHTOOL_MSG_USER_CNT, ETHTOOL_MSG_USER_MAX =3D (__ETHTOOL_MSG_USER_CNT - 1) @@ -951,6 +969,7 @@ enum { ETHTOOL_MSG_RSS_CREATE_NTF, ETHTOOL_MSG_RSS_DELETE_NTF, ETHTOOL_MSG_MSE_GET_REPLY, + ETHTOOL_MSG_PORT_GET_REPLY, =20 __ETHTOOL_MSG_KERNEL_CNT, ETHTOOL_MSG_KERNEL_MAX =3D (__ETHTOOL_MSG_KERNEL_CNT - 1) --=20 2.49.0 From nobody Sat Feb 7 12:34:43 2026 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 D759435F8A8 for ; Tue, 27 Jan 2026 13:42:52 +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=1769521374; cv=none; b=BIFrQ3NLq9EbGW+6a1FIxno40TsUIX/lKP4a+yOzjEdT/6njHFt+YcpXIFvpV61e/OPc48VoZVBYEeXqQKw8MAWaPOE4RmErohfEJKSKCsbyGDv0/9tugXpzYJlkzwUhO5gmg6u8wrO/COEY5uckwTpnEXB4OlnrWakxkyd1lwU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769521374; c=relaxed/simple; bh=pGmGlCKaaXi6n3kzu6pebk8nKqAgx61Vp2G+3MzMqzk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KtdY/BDFvZHAHn4gHLbGIIyiUTfl+OsL0U5UJX/fm0Rku0q9qsbmvuVtcaL7OeE6CVEKrDN9r0DDttOvW/IDUAhF23KRrA0rWoLoCpXSi3pL2iQltMsQzq9t6H90G/twoo/Z161P3aULt42VLKhza85RgpVSkWjfLVlZfTzuyd4= 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=lGbouBSY; 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="lGbouBSY" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id CB5CBC211C0; Tue, 27 Jan 2026 13:42:53 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id B8CF9606F5; Tue, 27 Jan 2026 13:42:51 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 2931A119A864D; Tue, 27 Jan 2026 14:42:48 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769521370; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=jZWnm/yA0XYyoiDagHR7AQL8Azf/LmljhrPAtB/4/yU=; b=lGbouBSY/2O+Q6kwm0zJvG+0f3lRnQVUF3oz2jxxNluHtlkQwU5p5gkjsIddEa5YSMct+P A65lCu9cRCSFaXmhokUjZDGoosBcdb2O5quYoKpFLyfTb6hZBhxolWa34qjAZRvUAl5T6e bu/lakRw6r8VV/oU3k6+KPMG4AjTMj2SwQAzMKcvw81I+ZOgQ4lql910x5AdYmlEEllo76 fVZbQr4DHDFWRlfAzCQ9KSMtBlrKlLqhtIanoWuJ/kBfsxiiuaHx1ALyBIWJyU7VST/pki ljlVrSWzZK/oMHvW3V3Prs4NF934G3cURHy53L4SgOpBcllja28pCUWyHQmVyg== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Russell King , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, Christophe Leroy , Herve Codina , Florian Fainelli , 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, Romain Gantois , Daniel Golle , Dimitri Fedrau Subject: [PATCH net-next 13/13] net: ethtool: Introduce ethtool command to list ports Date: Tue, 27 Jan 2026 14:42:01 +0100 Message-ID: <20260127134202.8208-14-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260127134202.8208-1-maxime.chevallier@bootlin.com> References: <20260127134202.8208-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" Expose the phy_port information to userspace, so that we can know how many ports are available on a given interface, as well as their capabilities. For MDI ports, we report the list of supported linkmodes based on what the PHY that drives this port says. For MII ports, i.e. empty SFP cages, we report the MII linkmodes that we can output on this port. Signed-off-by: Maxime Chevallier --- MAINTAINERS | 1 + net/ethtool/Makefile | 2 +- net/ethtool/netlink.c | 11 ++ net/ethtool/netlink.h | 5 + net/ethtool/port.c | 373 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 391 insertions(+), 1 deletion(-) create mode 100644 net/ethtool/port.c diff --git a/MAINTAINERS b/MAINTAINERS index c3df85fd5acd..a8272e169888 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18226,6 +18226,7 @@ F: Documentation/devicetree/bindings/net/ethernet-c= onnector.yaml F: Documentation/networking/phy-port.rst F: drivers/net/phy/phy_port.c F: include/linux/phy_port.h +F: net/ethtool/port.c K: struct\s+phy_port|phy_port_ =20 NETWORKING [GENERAL] diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile index 629c10916670..9b5b09670008 100644 --- a/net/ethtool/Makefile +++ b/net/ethtool/Makefile @@ -9,4 +9,4 @@ ethtool_nl-y :=3D netlink.o bitset.o strset.o linkinfo.o li= nkmodes.o rss.o \ channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \ tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \ module.o cmis_fw_update.o cmis_cdb.o pse-pd.o plca.o \ - phy.o tsconfig.o mse.o + phy.o tsconfig.o mse.o port.o diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 6e5f0f4f815a..82d94a2da55c 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -421,6 +421,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] =3D { [ETHTOOL_MSG_TSCONFIG_SET] =3D ðnl_tsconfig_request_ops, [ETHTOOL_MSG_PHY_GET] =3D ðnl_phy_request_ops, [ETHTOOL_MSG_MSE_GET] =3D ðnl_mse_request_ops, + [ETHTOOL_MSG_PORT_GET] =3D ðnl_port_request_ops, }; =20 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *= cb) @@ -1544,6 +1545,16 @@ static const struct genl_ops ethtool_genl_ops[] =3D { .policy =3D ethnl_mse_get_policy, .maxattr =3D ARRAY_SIZE(ethnl_mse_get_policy) - 1, }, + { + .cmd =3D ETHTOOL_MSG_PORT_GET, + .doit =3D ethnl_default_doit, + .start =3D ethnl_port_dump_start, + .dumpit =3D ethnl_port_dumpit, + .done =3D ethnl_port_dump_done, + .policy =3D ethnl_port_get_policy, + .maxattr =3D ARRAY_SIZE(ethnl_port_get_policy) - 1, + }, + }; =20 static const struct genl_multicast_group ethtool_nl_mcgrps[] =3D { diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h index 89010eaa67df..ea033992ba56 100644 --- a/net/ethtool/netlink.h +++ b/net/ethtool/netlink.h @@ -443,6 +443,7 @@ extern const struct ethnl_request_ops ethnl_mm_request_= ops; extern const struct ethnl_request_ops ethnl_phy_request_ops; extern const struct ethnl_request_ops ethnl_tsconfig_request_ops; extern const struct ethnl_request_ops ethnl_mse_request_ops; +extern const struct ethnl_request_ops ethnl_port_request_ops; =20 extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS = + 1]; extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_= FLAGS + 1]; @@ -499,6 +500,7 @@ extern const struct nla_policy ethnl_phy_get_policy[ETH= TOOL_A_PHY_HEADER + 1]; extern const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFI= G_HEADER + 1]; extern const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFI= G_MAX + 1]; extern const struct nla_policy ethnl_mse_get_policy[ETHTOOL_A_MSE_HEADER += 1]; +extern const struct nla_policy ethnl_port_get_policy[ETHTOOL_A_PORT_ID + 1= ]; =20 int ethnl_set_features(struct sk_buff *skb, struct genl_info *info); int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info); @@ -514,6 +516,9 @@ int ethnl_tsinfo_dumpit(struct sk_buff *skb, struct net= link_callback *cb); int ethnl_tsinfo_done(struct netlink_callback *cb); int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info); int ethnl_rss_delete_doit(struct sk_buff *skb, struct genl_info *info); +int ethnl_port_dump_start(struct netlink_callback *cb); +int ethnl_port_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int ethnl_port_dump_done(struct netlink_callback *cb); =20 extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN]; extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_G= STRING_LEN]; diff --git a/net/ethtool/port.c b/net/ethtool/port.c new file mode 100644 index 000000000000..efad1b88d909 --- /dev/null +++ b/net/ethtool/port.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2026 Bootlin + * + */ +#include "common.h" +#include "bitset.h" +#include "netlink.h" + +#include +#include +#include +#include + +struct port_req_info { + struct ethnl_req_info base; + u32 port_id; +}; + +struct port_reply_data { + struct ethnl_reply_data base; + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); + DECLARE_PHY_INTERFACE_MASK(interfaces); + u32 port_id; + bool mii; + bool sfp; + bool occupied; +}; + +#define PORT_REQINFO(__req_base) \ + container_of(__req_base, struct port_req_info, base) + +#define PORT_REPDATA(__reply_base) \ + container_of(__reply_base, struct port_reply_data, base) + +const struct nla_policy ethnl_port_get_policy[ETHTOOL_A_PORT_ID + 1] =3D { + [ETHTOOL_A_PORT_HEADER] =3D NLA_POLICY_NESTED(ethnl_header_policy), + [ETHTOOL_A_PORT_ID] =3D { .type =3D NLA_U32}, +}; + +static int port_parse_request(struct ethnl_req_info *req_info, + struct nlattr **tb, + struct netlink_ext_ack *extack) +{ + struct port_req_info *request =3D PORT_REQINFO(req_info); + + /* PORT id is required for GET requests */ + if (tb[ETHTOOL_A_PORT_ID]) + request->port_id =3D nla_get_u32(tb[ETHTOOL_A_PORT_ID]); + + if (!request->port_id) { + NL_SET_ERR_MSG(extack, "port id missing"); + return -ENODEV; + } + + return 0; +} + +static int port_prepare_data(const struct ethnl_req_info *req_info, + struct ethnl_reply_data *reply_data, + const struct genl_info *info) +{ + struct port_reply_data *reply =3D PORT_REPDATA(reply_data); + struct port_req_info *request =3D PORT_REQINFO(req_info); + struct phy_port *port; + + /* RTNL must be held while holding a ref to the phy_port. Here, caller + * holds RTNL. + */ + port =3D phy_link_topo_get_port(req_info->dev, request->port_id); + if (!port) + return -ENODEV; + + linkmode_copy(reply->supported, port->supported); + phy_interface_copy(reply->interfaces, port->interfaces); + reply->port_id =3D port->id; + reply->mii =3D port->is_mii; + reply->sfp =3D port->is_sfp; + reply->occupied =3D port->occupied; + + return 0; +} + +static int port_reply_size(const struct ethnl_req_info *req_info, + const struct ethnl_reply_data *reply_data) +{ + bool compact =3D req_info->flags & ETHTOOL_FLAG_COMPACT_BITSETS; + struct port_reply_data *reply =3D PORT_REPDATA(reply_data); + size_t size =3D 0; + int ret; + + /* ETHTOOL_A_PORT_ID */ + size +=3D nla_total_size(sizeof(u32)); + + if (!reply->mii) { + /* ETHTOOL_A_PORT_SUPPORTED_MODES */ + ret =3D ethnl_bitset_size(reply->supported, NULL, + __ETHTOOL_LINK_MODE_MASK_NBITS, + link_mode_names, compact); + if (ret < 0) + return ret; + + size +=3D ret; + } else { + /* ETHTOOL_A_PORT_SUPPORTED_INTERFACES */ + ret =3D ethnl_bitset_size(reply->interfaces, NULL, + PHY_INTERFACE_MODE_MAX, + phy_interface_names, compact); + if (ret < 0) + return ret; + } + + /* ETHTOOL_A_PORT_TYPE */ + size +=3D nla_total_size(sizeof(u8)); + + /* ETHTOOL_A_PORT_OCCUPIED */ + size +=3D nla_total_size(sizeof(u8)); + + return size; +} + +static int port_fill_reply(struct sk_buff *skb, + const struct ethnl_req_info *req_info, + const struct ethnl_reply_data *reply_data) +{ + bool compact =3D req_info->flags & ETHTOOL_FLAG_COMPACT_BITSETS; + struct port_reply_data *reply =3D PORT_REPDATA(reply_data); + int ret, port_type =3D ETHTOOL_PORT_TYPE_MDI; + + if (nla_put_u32(skb, ETHTOOL_A_PORT_ID, reply->port_id)) + return -EMSGSIZE; + + if (!reply->mii) { + ret =3D ethnl_put_bitset(skb, ETHTOOL_A_PORT_SUPPORTED_MODES, + reply->supported, NULL, + __ETHTOOL_LINK_MODE_MASK_NBITS, + link_mode_names, compact); + if (ret < 0) + return -EMSGSIZE; + } else { + ret =3D ethnl_put_bitset(skb, ETHTOOL_A_PORT_SUPPORTED_INTERFACES, + reply->interfaces, NULL, + PHY_INTERFACE_MODE_MAX, + phy_interface_names, compact); + if (ret < 0) + return -EMSGSIZE; + } + + if (reply->mii || reply->sfp) + port_type =3D ETHTOOL_PORT_TYPE_SFP; + + if (nla_put_u8(skb, ETHTOOL_A_PORT_TYPE, port_type) || + nla_put_u8(skb, ETHTOOL_A_PORT_OCCUPIED, reply->occupied)) + return -EMSGSIZE; + + return 0; +} + +struct port_dump_ctx { + struct port_req_info *req_info; + struct port_reply_data *reply_data; + unsigned long ifindex; + unsigned long pos_portid; +}; + +static struct port_dump_ctx * +port_dump_ctx_get(struct netlink_callback *cb) +{ + return (struct port_dump_ctx *)cb->ctx; +} + +int ethnl_port_dump_start(struct netlink_callback *cb) +{ + const struct genl_dumpit_info *info =3D genl_dumpit_info(cb); + struct port_dump_ctx *ctx =3D port_dump_ctx_get(cb); + struct nlattr **tb =3D info->info.attrs; + struct port_reply_data *reply_data; + struct port_req_info *req_info; + int ret; + + BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx)); + + req_info =3D kzalloc(sizeof(*req_info), GFP_KERNEL); + if (!req_info) + return -ENOMEM; + + reply_data =3D kmalloc(sizeof(*reply_data), GFP_KERNEL); + if (!reply_data) { + ret =3D -ENOMEM; + goto free_req_info; + } + + ret =3D ethnl_parse_header_dev_get(&req_info->base, tb[ETHTOOL_A_PORT_HEA= DER], + genl_info_net(&info->info), + info->info.extack, false); + if (ret < 0) + return ret; + + ctx->ifindex =3D 0; + + /* For filtered DUMP requests, let's just store the ifindex. We'll check + * again if the netdev is still there when looping over the netdev list + * in the DUMP loop. + */ + if (req_info->base.dev) { + ctx->ifindex =3D req_info->base.dev->ifindex; + netdev_put(req_info->base.dev, &req_info->base.dev_tracker); + req_info->base.dev =3D NULL; + } + + ctx->req_info =3D req_info; + ctx->reply_data =3D reply_data; + + return 0; + + kfree(reply_data); +free_req_info: + kfree(req_info); + + return ret; +} + +static int port_dump_one(struct sk_buff *skb, struct net_device *dev, + struct netlink_callback *cb) +{ + struct port_dump_ctx *ctx =3D port_dump_ctx_get(cb); + void *ehdr; + int ret; + + ehdr =3D ethnl_dump_put(skb, cb, ETHTOOL_A_PORT_HEADER); + if (!ehdr) + return -EMSGSIZE; + + memset(ctx->reply_data, 0, sizeof(struct port_reply_data)); + ctx->reply_data->base.dev =3D dev; + + rtnl_lock(); + netdev_lock_ops(dev); + + ret =3D port_prepare_data(&ctx->req_info->base, &ctx->reply_data->base, + genl_info_dump(cb)); + + netdev_unlock_ops(dev); + rtnl_unlock(); + + if (ret < 0) + goto out; + + ret =3D ethnl_fill_reply_header(skb, dev, ETHTOOL_A_PORT_HEADER); + if (ret < 0) + goto out; + + ret =3D port_fill_reply(skb, &ctx->req_info->base, &ctx->reply_data->base= ); + +out: + ctx->reply_data->base.dev =3D NULL; + if (ret < 0) + genlmsg_cancel(skb, ehdr); + else + genlmsg_end(skb, ehdr); + + return ret; +} + +static int port_dump_one_dev(struct sk_buff *skb, struct netlink_callback = *cb) +{ + struct port_dump_ctx *ctx =3D port_dump_ctx_get(cb); + struct net_device *dev; + struct phy_port *port; + int ret; + + dev =3D ctx->req_info->base.dev; + + if (!dev->link_topo) + return 0; + + xa_for_each_start(&dev->link_topo->ports, ctx->pos_portid, port, + ctx->pos_portid) { + ctx->req_info->port_id =3D ctx->pos_portid; + + ret =3D port_dump_one(skb, dev, cb); + if (ret) + return ret; + } + + ctx->pos_portid =3D 0; + + return 0; +} + +static int port_dump_all_dev(struct sk_buff *skb, struct netlink_callback = *cb) +{ + struct port_dump_ctx *ctx =3D port_dump_ctx_get(cb); + struct net *net =3D sock_net(skb->sk); + netdevice_tracker dev_tracker; + struct net_device *dev; + int ret =3D 0; + + rcu_read_lock(); + for_each_netdev_dump(net, dev, ctx->ifindex) { + netdev_hold(dev, &dev_tracker, GFP_ATOMIC); + rcu_read_unlock(); + + ctx->req_info->base.dev =3D dev; + ret =3D port_dump_one_dev(skb, cb); + + rcu_read_lock(); + netdev_put(dev, &dev_tracker); + ctx->req_info->base.dev =3D NULL; + + if (ret < 0 && ret !=3D -EOPNOTSUPP) { + if (likely(skb->len)) + ret =3D skb->len; + break; + } + ret =3D 0; + } + rcu_read_unlock(); + + return ret; +} + +int ethnl_port_dumpit(struct sk_buff *skb, struct netlink_callback *cb) +{ + const struct genl_dumpit_info *info =3D genl_dumpit_info(cb); + struct port_dump_ctx *ctx =3D port_dump_ctx_get(cb); + int ret =3D 0; + + if (ctx->ifindex) { + netdevice_tracker dev_tracker; + struct net_device *dev; + + dev =3D netdev_get_by_index(genl_info_net(&info->info), + ctx->ifindex, &dev_tracker, + GFP_KERNEL); + if (!dev) + return -ENODEV; + + ctx->req_info->base.dev =3D dev; + ret =3D port_dump_one_dev(skb, cb); + if (ret < 0 && ret !=3D -EOPNOTSUPP && likely(skb->len)) + ret =3D skb->len; + + netdev_put(dev, &dev_tracker); + } else { + ret =3D port_dump_all_dev(skb, cb); + } + + return ret; +} + +int ethnl_port_dump_done(struct netlink_callback *cb) +{ + struct port_dump_ctx *ctx =3D port_dump_ctx_get(cb); + + kfree(ctx->req_info); + kfree(ctx->reply_data); + + return 0; +} + +const struct ethnl_request_ops ethnl_port_request_ops =3D { + .request_cmd =3D ETHTOOL_MSG_PORT_GET, + .reply_cmd =3D ETHTOOL_MSG_PORT_GET_REPLY, + .hdr_attr =3D ETHTOOL_A_PORT_HEADER, + .req_info_size =3D sizeof(struct port_req_info), + .reply_data_size =3D sizeof(struct port_reply_data), + + .parse_request =3D port_parse_request, + .prepare_data =3D port_prepare_data, + .reply_size =3D port_reply_size, + .fill_reply =3D port_fill_reply, +}; --=20 2.49.0