public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing
@ 2026-01-27 13:41 Maxime Chevallier
  2026-01-27 13:41 ` [PATCH net-next 01/13] net: phy: phy_port: Correctly recompute the port's linkmodes Maxime Chevallier
                   ` (13 more replies)
  0 siblings, 14 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:41 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

Hello everyone,

This series is another step towards dealing with multi-port interfaces.

It build on the recent addition of phy_port representation to enable
listing the front-facing ports of an interface. For now, we don't control
these ports, we merely list their presence and their capabilities.

As the most common use-case of multi-port interfaces is combo-ports that
provide both RJ45 and SFP connectors on a single MAC, there's a lot of
SFP stuff in this series.

This series is in 2 main parts. The first one aims at representing the
SFP cages and modules using phy_port, as combo-ports with RJ45 + SFP are
by far the most common cases for multi-connector setups.

The second part is the netlink interface to list those ports, now that
most use-cases are covered.

Let's see what we can do with some examples of the new ethtool API :

- Get MII interfaces supported by an empty SFP cage :

# ethtool --show-ports eth3

Port for eth3:
	Port id: 1
	Occupied: no
	Supported MII interfaces : sgmii, 1000base-x, 2500base-x
	Port type: sfp


- Get Combo-ports supported modes, on each port :

# ethtool --show-ports eth0

Port for eth0:
	Port id: 1
	Occupied: no
	Supported link modes:  10baseT/Half 10baseT/Full
	                       100baseT/Half 100baseT/Full
	                       1000baseT/Half 1000baseT/Full
	                       10000baseT/Full
	                       2500baseT/Full
	                       5000baseT/Full
	Port type: mdi

Port for eth0:
	Port id: 2
	Occupied: no
	Supported MII interfaces : 10gbase-r
	Port type: sfp
	

- Get Achievable linkmodes on a SFP module (combo port with a DAC in the
SFP cage)

# ethtool --show-ports eth1

Port for eth1:
	Port id: 1
	Occupied: no
	Supported link modes:  10baseT/Half 10baseT/Full
	                       100baseT/Half 100baseT/Full
	                       1000baseT/Half 1000baseT/Full
	                       10000baseT/Full
	                       2500baseT/Full
	                       5000baseT/Full
	Port type: mdi

Port for eth1:
	Port id: 2
	Occupied: yes
	Supported MII interfaces : 10gbase-r
	Port type: sfp

Port for eth1:
	Port id: 3
	Occupied: no
	Supported link modes:  10000baseCR/Full
	Port type: mdi

Note that here, we have 3 ports :
 - The Copper port
 - The SFP Cage itself, marked as 'occupied'
 - The SFP module

This series builds on top of phy_port and phy_link_topology to allow
tracking the ports of an interface. We maintain a list of supported
linkmodes/interfaces on each port, which allows for fine-grained
reporting of each port's capability.

What this series doesn't do :
 - We don't support selecting which port is active. This is the next step.
 - We only support PHY-driven combo ports. The end-goal of this whole
   journey that started with phy_link_topology is to get support for MII
   muxes, such as the one we have on the Turris Omnia. This will eventually
   be upstreamed as well.

If you want to play around with it, here's [1] the patched ethtool that I've
been using to produce the outputs above.

Thanks !

Maxime

[1] : https://github.com/minimaxwell/ethtool/tree/mc/ethtool_port

Maxime Chevallier (13):
  net: phy: phy_port: Correctly recompute the port's linkmodes
  net: phy: phy_link_topology: Add a helper for opportunistic alloc
  net: phy: phy_link_topology: Track ports in phy_link_topology
  net: phylink: Register a phy_port for MAC-driven SFP busses
  net: phy: Create SFP phy_port before registering usptream
  net: sfp: Add a sfp-bus ops when connecting a module without PHY
  net: phy: Represent PHY-less SFP modules with phy_port
  net: phylink: Represent PHY-less SFP modules with phy_port
  net: phy: phy_port: Store information about a MII port's occupancy
  net: phy: phy_link_topology: Add a helper to retrieve ports
  net: phy: store phy_modes in a static array
  netlink: specs: Add ethernet port listing with ethtool
  net: ethtool: Introduce ethtool command to list ports

 Documentation/netlink/specs/ethtool.yaml      |  50 +++
 Documentation/networking/ethtool-netlink.rst  |  35 ++
 MAINTAINERS                                   |   1 +
 drivers/net/phy/phy-caps.h                    |   2 +
 drivers/net/phy/phy_caps.c                    |  26 ++
 drivers/net/phy/phy_device.c                  | 104 ++++-
 drivers/net/phy/phy_link_topology.c           |  80 +++-
 drivers/net/phy/phy_port.c                    |   9 +-
 drivers/net/phy/phylink.c                     | 121 ++++++
 drivers/net/phy/sfp-bus.c                     |  20 +
 drivers/net/phy/sfp.c                         |  12 +
 drivers/net/phy/sfp.h                         |   2 +
 include/linux/phy.h                           |  88 +----
 include/linux/phy_link_topology.h             |  34 ++
 include/linux/phy_port.h                      |   5 +
 include/linux/sfp.h                           |   5 +
 .../uapi/linux/ethtool_netlink_generated.h    |  19 +
 net/ethtool/Makefile                          |   2 +-
 net/ethtool/common.c                          |  44 +++
 net/ethtool/netlink.c                         |  11 +
 net/ethtool/netlink.h                         |   5 +
 net/ethtool/port.c                            | 373 ++++++++++++++++++
 22 files changed, 943 insertions(+), 105 deletions(-)
 create mode 100644 net/ethtool/port.c

-- 
2.49.0


^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH net-next 01/13] net: phy: phy_port: Correctly recompute the port's linkmodes
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
@ 2026-01-27 13:41 ` Maxime Chevallier
  2026-01-27 14:00   ` Kory Maincent
  2026-01-27 13:41 ` [PATCH net-next 02/13] net: phy: phy_link_topology: Add a helper for opportunistic alloc Maxime Chevallier
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:41 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

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 <maxime.chevallier@bootlin.com>
---
 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;
 
 	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) = {0};
+
+		phy_caps_medium_get_supported(med_supported, i, port->pairs);
+		linkmode_or(supported, supported, med_supported);
 	}
 
+	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
 	 */
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH net-next 02/13] net: phy: phy_link_topology: Add a helper for opportunistic alloc
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
  2026-01-27 13:41 ` [PATCH net-next 01/13] net: phy: phy_port: Correctly recompute the port's linkmodes Maxime Chevallier
@ 2026-01-27 13:41 ` Maxime Chevallier
  2026-01-27 13:41 ` [PATCH net-next 03/13] net: phy: phy_link_topology: Track ports in phy_link_topology Maxime Chevallier
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:41 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

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 <maxime.chevallier@bootlin.com>
---
 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_device *dev)
 	return 0;
 }
 
+static struct phy_link_topology *phy_link_topo_get_or_alloc(struct net_device *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 = 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 = dev->link_topo;
+	struct phy_link_topology *topo;
 	struct phy_device_node *pdn;
 	int ret;
 
-	if (!topo) {
-		ret = netdev_alloc_phy_link_topology(dev);
-		if (ret)
-			return ret;
-
-		topo = dev->link_topo;
-	}
+	topo = phy_link_topo_get_or_alloc(dev);
+	if (IS_ERR(topo))
+		return PTR_ERR(topo);
 
 	pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
 	if (!pdn)
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH net-next 03/13] net: phy: phy_link_topology: Track ports in phy_link_topology
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
  2026-01-27 13:41 ` [PATCH net-next 01/13] net: phy: phy_port: Correctly recompute the port's linkmodes Maxime Chevallier
  2026-01-27 13:41 ` [PATCH net-next 02/13] net: phy: phy_link_topology: Add a helper for opportunistic alloc Maxime Chevallier
@ 2026-01-27 13:41 ` Maxime Chevallier
  2026-01-27 13:41 ` [PATCH net-next 04/13] net: phylink: Register a phy_port for MAC-driven SFP busses Maxime Chevallier
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:41 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

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 <maxime.chevallier@bootlin.com>
---
 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 @@
  */
 
 #include <linux/phy_link_topology.h>
+#include <linux/phy_port.h>
 #include <linux/phy.h>
 #include <linux/rtnetlink.h>
 #include <linux/xarray.h>
@@ -22,6 +23,9 @@ static int netdev_alloc_phy_link_topology(struct net_device *dev)
 	xa_init_flags(&topo->phys, XA_FLAGS_ALLOC1);
 	topo->next_phy_index = 1;
 
+	xa_init_flags(&topo->ports, XA_FLAGS_ALLOC1);
+	topo->next_port_index = 1;
+
 	dev->link_topo = topo;
 
 	return 0;
@@ -44,12 +48,45 @@ static struct phy_link_topology *phy_link_topo_get_or_alloc(struct net_device *d
 	return dev->link_topo;
 }
 
+int phy_link_topo_add_port(struct net_device *dev, struct phy_port *port)
+{
+	struct phy_link_topology *topo;
+	int ret;
+
+	topo = 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 = xa_insert(&topo->ports, port->id, port, GFP_KERNEL);
+	else
+		ret = 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 = 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;
 
 	topo = 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;
 
+	/* Add all the PHY's ports to the topology */
+	list_for_each_entry(port, &phy->ports, head) {
+		ret = phy_link_topo_add_port(dev, port);
+		if (ret)
+			goto del_ports;
+	}
+
 	return 0;
 
+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 = dev->link_topo;
 	struct phy_device_node *pdn;
+	struct phy_port *port;
 
 	if (!topo)
 		return;
 
+	list_for_each_entry(port, &phy->ports, head)
+		phy_link_topo_del_port(dev, port);
+
 	pdn = xa_erase(&topo->phys, phy->phyindex);
 
 	/* 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_topology.h
index 68a59e25821c..66bceff72b19 100644
--- a/include/linux/phy_link_topology.h
+++ b/include/linux/phy_link_topology.h
@@ -16,11 +16,15 @@
 
 struct xarray;
 struct phy_device;
+struct phy_port;
 struct sfp_bus;
 
 struct phy_link_topology {
 	struct xarray phys;
 	u32 next_phy_index;
+
+	struct xarray ports;
+	u32 next_port_index;
 };
 
 struct phy_device_node {
@@ -43,6 +47,9 @@ int phy_link_topo_add_phy(struct net_device *dev,
 
 void phy_link_topo_del_phy(struct net_device *dev, struct phy_device *phy);
 
+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_device *dev,
 {
 }
 
+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 interface
  *
+ * @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 {
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH net-next 04/13] net: phylink: Register a phy_port for MAC-driven SFP busses
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
                   ` (2 preceding siblings ...)
  2026-01-27 13:41 ` [PATCH net-next 03/13] net: phy: phy_link_topology: Track ports in phy_link_topology Maxime Chevallier
@ 2026-01-27 13:41 ` Maxime Chevallier
  2026-01-27 13:41 ` [PATCH net-next 05/13] net: phy: Create SFP phy_port before registering usptream Maxime Chevallier
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:41 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

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 <maxime.chevallier@bootlin.com>
---
 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 <linux/of_mdio.h>
 #include <linux/phy.h>
 #include <linux/phy_fixed.h>
+#include <linux/phy_link_topology.h>
+#include <linux/phy_port.h>
 #include <linux/phylink.h>
 #include <linux/rtnetlink.h>
 #include <linux/spinlock.h>
@@ -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;
 
 	struct eee_config eee_cfg;
 
@@ -1757,6 +1760,46 @@ static void phylink_fixed_poll(struct timer_list *t)
 
 static const struct sfp_upstream_ops sfp_phylink_ops;
 
+static int phylink_create_sfp_port(struct phylink *pl)
+{
+	struct phy_port *port;
+	int ret = 0;
+
+	if (!pl->netdev || !pl->sfp_bus)
+		return 0;
+
+	port = phy_port_alloc();
+	if (!port)
+		return -ENOMEM;
+
+	port->is_sfp = true;
+	port->is_mii = true;
+	port->active = true;
+
+	phy_interface_and(port->interfaces, pl->config->supported_interfaces,
+			  phylink_sfp_interfaces);
+	phy_port_update_supported(port);
+
+	ret = phy_link_topo_add_port(pl->netdev, port);
+	if (ret)
+		phy_port_destroy(port);
+	else
+		pl->sfp_bus_port = 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 = 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,
 
 	pl->sfp_bus = bus;
 
+	ret = phylink_create_sfp_port(pl);
+	if (ret) {
+		sfp_bus_put(bus);
+		return ret;
+	}
+
 	ret = sfp_bus_add_upstream(bus, pl, &sfp_phylink_ops);
 	sfp_bus_put(bus);
 
+	if (ret)
+		phylink_destroy_sfp_port(pl);
+
 	return ret;
 }
 
@@ -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);
 
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH net-next 05/13] net: phy: Create SFP phy_port before registering usptream
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
                   ` (3 preceding siblings ...)
  2026-01-27 13:41 ` [PATCH net-next 04/13] net: phylink: Register a phy_port for MAC-driven SFP busses Maxime Chevallier
@ 2026-01-27 13:41 ` Maxime Chevallier
  2026-01-28 15:49   ` Romain Gantois
  2026-01-27 13:41 ` [PATCH net-next 06/13] net: sfp: Add a sfp-bus ops when connecting a module without PHY Maxime Chevallier
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:41 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

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 <maxime.chevallier@bootlin.com>
---
 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--;
 }
 
-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 = phy_port_alloc();
 	int ret;
 
 	if (!port)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	port->parent_type = PHY_PORT_PHY;
 	port->phy = phydev;
@@ -1686,10 +1686,12 @@ static int phy_setup_sfp_port(struct phy_device *phydev)
 	 * when attaching the port to the phydev.
 	 */
 	ret = phy_add_port(phydev, port);
-	if (ret)
+	if (ret) {
 		phy_port_destroy(port);
+		return ERR_PTR(ret);
+	}
 
-	return ret;
+	return port;
 }
 
 /**
@@ -1698,22 +1700,32 @@ static int phy_setup_sfp_port(struct phy_device *phydev)
  */
 static int phy_sfp_probe(struct phy_device *phydev)
 {
+	struct phy_port *port;
 	struct sfp_bus *bus;
-	int ret = 0;
+	int ret;
+
+	if (!phydev->mdio.dev.fwnode)
+		return 0;
 
-	if (phydev->mdio.dev.fwnode) {
-		bus = sfp_bus_find_fwnode(phydev->mdio.dev.fwnode);
-		if (IS_ERR(bus))
-			return PTR_ERR(bus);
+	bus = sfp_bus_find_fwnode(phydev->mdio.dev.fwnode);
+	if (IS_ERR(bus))
+		return PTR_ERR(bus);
 
-		phydev->sfp_bus = bus;
+	phydev->sfp_bus = bus;
 
-		ret = sfp_bus_add_upstream(bus, phydev, &sfp_phydev_ops);
-		sfp_bus_put(bus);
+	if (bus) {
+		port = phy_setup_sfp_port(phydev);
+		if (IS_ERR(port)) {
+			sfp_bus_put(bus);
+			return PTR_ERR(port);
+		}
 	}
 
-	if (!ret && phydev->sfp_bus)
-		ret = phy_setup_sfp_port(phydev);
+	ret = sfp_bus_add_upstream(bus, phydev, &sfp_phydev_ops);
+	sfp_bus_put(bus);
+
+	if (ret && port)
+		phy_del_port(phydev, port);
 
 	return ret;
 }
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH net-next 06/13] net: sfp: Add a sfp-bus ops when connecting a module without PHY
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
                   ` (4 preceding siblings ...)
  2026-01-27 13:41 ` [PATCH net-next 05/13] net: phy: Create SFP phy_port before registering usptream Maxime Chevallier
@ 2026-01-27 13:41 ` Maxime Chevallier
  2026-01-30 16:19   ` Russell King (Oracle)
  2026-01-27 13:41 ` [PATCH net-next 07/13] net: phy: Represent PHY-less SFP modules with phy_port Maxime Chevallier
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:41 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

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 <maxime.chevallier@bootlin.com>
---
 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);
 
+int sfp_module_connect_nophy(struct sfp_bus *bus)
+{
+	const struct sfp_upstream_ops *ops = 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 = 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 = 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,
 
 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 addr, bool is_c45)
 	return 0;
 }
 
+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 int event)
 			sfp_sm_next(sfp, SFP_S_FAIL, 0);
 			break;
 		}
+		if (!sfp->mod_phy) {
+			ret = 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 sfp_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);
 };
 
 #if IS_ENABLED(CONFIG_SFP)
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH net-next 07/13] net: phy: Represent PHY-less SFP modules with phy_port
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
                   ` (5 preceding siblings ...)
  2026-01-27 13:41 ` [PATCH net-next 06/13] net: sfp: Add a sfp-bus ops when connecting a module without PHY Maxime Chevallier
@ 2026-01-27 13:41 ` Maxime Chevallier
  2026-01-28 15:54   ` Romain Gantois
  2026-01-27 13:41 ` [PATCH net-next 08/13] net: phylink: " Maxime Chevallier
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:41 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

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 <maxime.chevallier@bootlin.com>
---
 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 *supported,
 				   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 long *from,
+				     const unsigned long *interfaces);
 
 #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 *linkmodes)
 	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 achieve
+ * 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) = {};
+	unsigned int ifaces_caps = 0;
+	phy_interface_t interface;
+
+	for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
+		ifaces_caps |= 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);
 }
 
+static int phy_sfp_connect_nophy(void *upstream)
+{
+	struct phy_device *phydev = upstream;
+	const struct sfp_module_caps *caps;
+	struct phy_port *port;
+	int ret = 0;
+
+	/* Create mod port */
+	port = phy_port_alloc();
+	if (!port)
+		return -ENOMEM;
+
+	port->active = true;
+
+	caps = 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 = 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 = port;
+
+	return 0;
+}
+
+static void phy_sfp_disconnect_nophy(void *upstream)
+{
+	struct phy_device *phydev = 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 = NULL;
+}
+
 static const struct sfp_upstream_ops sfp_phydev_ops = {
 	.attach = phy_sfp_attach,
 	.detach = phy_sfp_detach,
@@ -1618,6 +1665,8 @@ static const struct sfp_upstream_ops sfp_phydev_ops = {
 	.link_down = phy_sfp_link_down,
 	.connect_phy = phy_sfp_connect_phy,
 	.disconnect_phy = phy_sfp_disconnect_phy,
+	.connect_nophy = phy_sfp_connect_nophy,
+	.disconnect_nophy = phy_sfp_disconnect_nophy,
 };
 
 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 = NULL;
 	struct sfp_bus *bus;
 	int ret;
 
@@ -1727,6 +1776,8 @@ static int phy_sfp_probe(struct phy_device *phydev)
 	if (ret && port)
 		phy_del_port(phydev, port);
 
+	phydev->sfp_bus_port = port;
+
 	return ret;
 }
 
@@ -1816,6 +1867,12 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
 		err = phy_link_topo_add_phy(dev, phydev, PHY_UPSTREAM_MAC, dev);
 		if (err)
 			goto error;
+
+		if (phydev->mod_port) {
+			err = phy_link_topo_add_port(dev, phydev->mod_port);
+			if (err)
+				goto error;
+		}
 	}
 
 	/* 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 = NULL;
 		phydev->attached_dev = NULL;
 		phy_link_topo_del_phy(dev, phydev);
+		if (phydev->mod_port)
+			phy_link_topo_del_port(dev, phydev->mod_port);
 	}
 
 	phydev->phy_link_change = NULL;
@@ -3816,6 +3875,7 @@ static int phy_remove(struct device *dev)
 
 	sfp_bus_del_upstream(phydev->sfp_bus);
 	phydev->sfp_bus = NULL;
+	phydev->sfp_bus_port = NULL;
 
 	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: in 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;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH net-next 08/13] net: phylink: Represent PHY-less SFP modules with phy_port
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
                   ` (6 preceding siblings ...)
  2026-01-27 13:41 ` [PATCH net-next 07/13] net: phy: Represent PHY-less SFP modules with phy_port Maxime Chevallier
@ 2026-01-27 13:41 ` Maxime Chevallier
  2026-01-28 16:01   ` Romain Gantois
  2026-01-27 13:41 ` [PATCH net-next 09/13] net: phy: phy_port: Store information about a MII port's occupancy Maxime Chevallier
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:41 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

Let phylink handle the phy_port for PHY-less modules, and register it to
the topology.

Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
 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;
 
 	struct eee_config eee_cfg;
 
@@ -1786,13 +1787,31 @@ static int phylink_create_sfp_port(struct phylink *pl)
 	else
 		pl->sfp_bus_port = port;
 
+	if (pl->mod_port) {
+		ret = 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;
 }
 
 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);
+	}
 
 	if (pl->sfp_bus_port)
 		phy_port_destroy(pl->sfp_bus_port);
@@ -3998,6 +4017,49 @@ static void phylink_sfp_disconnect_phy(void *upstream,
 	phylink_disconnect_phy(upstream);
 }
 
+static int phylink_sfp_connect_nophy(void *upstream)
+{
+	const struct sfp_module_caps *caps;
+	struct phylink *pl = upstream;
+	struct phy_port *port;
+	int ret = 0;
+
+	/* Create mod port */
+	port = phy_port_alloc();
+	if (!port)
+		return -ENOMEM;
+
+	port->active = true;
+
+	caps = 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 = phy_link_topo_add_port(pl->netdev, port);
+		if (ret) {
+			phy_port_destroy(port);
+			return ret;
+		}
+	}
+
+	pl->mod_port = port;
+
+	return 0;
+}
+
+static void phylink_sfp_disconnect_nophy(void *upstream)
+{
+	struct phylink *pl = upstream;
+
+	if (pl->netdev)
+		phy_link_topo_del_port(pl->netdev, pl->mod_port);
+
+	phy_port_destroy(pl->mod_port);
+	pl->mod_port = NULL;
+}
+
 static const struct sfp_upstream_ops sfp_phylink_ops = {
 	.attach = phylink_sfp_attach,
 	.detach = phylink_sfp_detach,
@@ -4009,6 +4071,8 @@ static const struct sfp_upstream_ops sfp_phylink_ops = {
 	.link_down = phylink_sfp_link_down,
 	.connect_phy = phylink_sfp_connect_phy,
 	.disconnect_phy = phylink_sfp_disconnect_phy,
+	.connect_nophy = phylink_sfp_connect_nophy,
+	.disconnect_nophy = phylink_sfp_disconnect_nophy,
 };
 
 /* Helpers for MAC drivers */
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH net-next 09/13] net: phy: phy_port: Store information about a MII port's occupancy
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
                   ` (7 preceding siblings ...)
  2026-01-27 13:41 ` [PATCH net-next 08/13] net: phylink: " Maxime Chevallier
@ 2026-01-27 13:41 ` Maxime Chevallier
  2026-01-28 16:08   ` Romain Gantois
  2026-01-27 13:41 ` [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports Maxime Chevallier
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:41 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

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 <maxime.chevallier@bootlin.com>
---
 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)
 		}
 	}
 
+	phydev->sfp_bus_port->occupied = 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 = upstream;
 
+	phydev->sfp_bus_port->occupied = false;
+
 	if (phydev->attached_dev)
 		phy_link_topo_del_port(phydev->attached_dev, phydev->mod_port);
 
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)
 		}
 	}
 
+	pl->sfp_bus_port->occupied = true;
+
 	pl->mod_port = port;
 
 	return 0;
@@ -4053,6 +4055,8 @@ static void phylink_sfp_disconnect_nophy(void *upstream)
 {
 	struct phylink *pl = upstream;
 
+	pl->sfp_bus_port->occupied = false;
+
 	if (pl->netdev)
 		phy_link_topo_del_port(pl->netdev, pl->mod_port);
 
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;
 };
 
 struct phy_port *phy_port_alloc(void);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
                   ` (8 preceding siblings ...)
  2026-01-27 13:41 ` [PATCH net-next 09/13] net: phy: phy_port: Store information about a MII port's occupancy Maxime Chevallier
@ 2026-01-27 13:41 ` Maxime Chevallier
  2026-01-27 22:23   ` kernel test robot
                     ` (2 more replies)
  2026-01-27 13:41 ` [PATCH net-next 11/13] net: phy: store phy_modes in a static array Maxime Chevallier
                   ` (3 subsequent siblings)
  13 siblings, 3 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:41 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

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 <maxime.chevallier@bootlin.com>
---
 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_topology.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 phyindex)
 	return NULL;
 }
 
+static inline struct phy_port *
+phy_link_topo_get_port(struct net_device *dev, u32 port_id)
+{
+	struct phy_link_topology *topo = 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 phyindex)
 {
 	return NULL;
 }
+
+phy_link_topo_get_port(struct net_device *dev, u32 port_id)
+{
+	return NULL;
+}
 #endif
 
 #endif /* __PHY_LINK_TOPOLOGY_H */
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH net-next 11/13] net: phy: store phy_modes in a static array
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
                   ` (9 preceding siblings ...)
  2026-01-27 13:41 ` [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports Maxime Chevallier
@ 2026-01-27 13:41 ` Maxime Chevallier
  2026-01-27 13:42 ` [PATCH net-next 12/13] netlink: specs: Add ethernet port listing with ethtool Maxime Chevallier
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:41 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

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 <maxime.chevallier@bootlin.com>
---
 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 long *intf)
 	__set_bit(PHY_INTERFACE_MODE_RGMII_TXID, intf);
 }
 
+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 long *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];
 }
 
 /**
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_GSTRING_LEN] = {
 };
 static_assert(ARRAY_SIZE(ethtool_link_medium_names) == __ETHTOOL_LINK_MEDIUM_LAST);
 
+const char phy_interface_names[][ETH_GSTRING_LEN] = {
+	[PHY_INTERFACE_MODE_NA] =	"",
+	[PHY_INTERFACE_MODE_INTERNAL] =	"internal",
+	[PHY_INTERFACE_MODE_MII] =	"mii",
+	[PHY_INTERFACE_MODE_GMII] =	"gmii",
+	[PHY_INTERFACE_MODE_SGMII] =	"sgmii",
+	[PHY_INTERFACE_MODE_TBI] =	"tbi",
+	[PHY_INTERFACE_MODE_REVMII] =	"rev-mii",
+	[PHY_INTERFACE_MODE_RMII] =	"rmii",
+	[PHY_INTERFACE_MODE_REVRMII] =	"rev-rmii",
+	[PHY_INTERFACE_MODE_RGMII] =	"rgmii",
+	[PHY_INTERFACE_MODE_RGMII_ID] = "rgmii-id",
+	[PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid",
+	[PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
+	[PHY_INTERFACE_MODE_RTBI] =	"rtbi",
+	[PHY_INTERFACE_MODE_SMII] =	"smii",
+	[PHY_INTERFACE_MODE_XGMII] =	"xgmii",
+	[PHY_INTERFACE_MODE_XLGMII] =	"xlgmii",
+	[PHY_INTERFACE_MODE_MOCA] =	"moca",
+	[PHY_INTERFACE_MODE_PSGMII] =	"psgmii",
+	[PHY_INTERFACE_MODE_QSGMII] =	"qsgmii",
+	[PHY_INTERFACE_MODE_TRGMII] =	"trgmii",
+	[PHY_INTERFACE_MODE_1000BASEX] = "1000base-x",
+	[PHY_INTERFACE_MODE_1000BASEKX] = "1000base-kx",
+	[PHY_INTERFACE_MODE_2500BASEX] = "2500base-x",
+	[PHY_INTERFACE_MODE_5GBASER] =	"5gbase-r",
+	[PHY_INTERFACE_MODE_RXAUI] =	"rxaui",
+	[PHY_INTERFACE_MODE_XAUI] =	"xaui",
+	[PHY_INTERFACE_MODE_10GBASER] =	"10gbase-r",
+	[PHY_INTERFACE_MODE_25GBASER] =	"25gbase-r",
+	[PHY_INTERFACE_MODE_USXGMII] =	"usxgmii",
+	[PHY_INTERFACE_MODE_10GKR] =	"10gbase-kr",
+	[PHY_INTERFACE_MODE_100BASEX] =	"100base-x",
+	[PHY_INTERFACE_MODE_QUSGMII] =	"qusgmii",
+	[PHY_INTERFACE_MODE_10G_QXGMII] = "10g-qxgmii",
+	[PHY_INTERFACE_MODE_50GBASER] =	"50gbase-r",
+	[PHY_INTERFACE_MODE_LAUI] =	"laui",
+	[PHY_INTERFACE_MODE_100GBASEP] = "100gbase-p",
+	[PHY_INTERFACE_MODE_MIILITE] =	"mii-lite",
+
+};
+static_assert(ARRAY_SIZE(phy_interface_names) == PHY_INTERFACE_MODE_MAX);
+EXPORT_SYMBOL_GPL(phy_interface_names);
+
 const char netif_msg_class_names[][ETH_GSTRING_LEN] = {
 	[NETIF_MSG_DRV_BIT]		= "drv",
 	[NETIF_MSG_PROBE_BIT]		= "probe",
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH net-next 12/13] netlink: specs: Add ethernet port listing with ethtool
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
                   ` (10 preceding siblings ...)
  2026-01-27 13:41 ` [PATCH net-next 11/13] net: phy: store phy_modes in a static array Maxime Chevallier
@ 2026-01-27 13:42 ` Maxime Chevallier
  2026-01-27 13:42 ` [PATCH net-next 13/13] net: ethtool: Introduce ethtool command to list ports Maxime Chevallier
  2026-01-27 21:07 ` [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Jakub Kicinski
  13 siblings, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:42 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

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 <maxime.chevallier@bootlin.com>
---
 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/netlink/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]
 
 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
 
 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
 
 mcast-groups:
   list:
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/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``.
 
+PORT_GET
+========
+
+Retrieve information about the physical connection points of a network device,
+referred to as "ports". User needs to specify a PORT_ID for the DO operation,
+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:
+
+====================================  ======  =================================
+  ``ETHTOOL_A_PORT_HEADER``             nested  request header
+  ``ETHTOOL_A_PORT_ID``                 u32     port id
+  ====================================  ======  ===============================
+
+Kernel response contents:
+
+  =====================================   ======  =============================
+  ``ETHTOOL_A_PORT_HEADER``               nested  request header
+  ``ETHTOOL_A_PORT_ID``                   u32     the port's unique identifier,
+                                                  per netdevice.
+  ``ETHTOOL_A_PORT_SUPPORTED_MODES``      bitset  bitset of supported linkmodes
+  ``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, indicates
+                                                  if the port is connected
+                                                  another device that could
+                                                  expose a MDI
+  =====================================   ======  =============================
+
 Request translation
 ===================
 
@@ -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``
   =================================== =====================================
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 = 64,
 };
 
+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 = (__ETHTOOL_A_MSE_CNT - 1)
 };
 
+enum {
+	ETHTOOL_A_PORT_HEADER = 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 = (__ETHTOOL_A_PORT_CNT - 1)
+};
+
 enum {
 	ETHTOOL_MSG_USER_NONE = 0,
 	ETHTOOL_MSG_STRSET_GET = 1,
@@ -890,6 +907,7 @@ enum {
 	ETHTOOL_MSG_RSS_CREATE_ACT,
 	ETHTOOL_MSG_RSS_DELETE_ACT,
 	ETHTOOL_MSG_MSE_GET,
+	ETHTOOL_MSG_PORT_GET,
 
 	__ETHTOOL_MSG_USER_CNT,
 	ETHTOOL_MSG_USER_MAX = (__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,
 
 	__ETHTOOL_MSG_KERNEL_CNT,
 	ETHTOOL_MSG_KERNEL_MAX = (__ETHTOOL_MSG_KERNEL_CNT - 1)
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH net-next 13/13] net: ethtool: Introduce ethtool command to list ports
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
                   ` (11 preceding siblings ...)
  2026-01-27 13:42 ` [PATCH net-next 12/13] netlink: specs: Add ethernet port listing with ethtool Maxime Chevallier
@ 2026-01-27 13:42 ` Maxime Chevallier
  2026-01-27 23:16   ` kernel test robot
  2026-01-27 21:07 ` [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Jakub Kicinski
  13 siblings, 1 reply; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 13:42 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

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 <maxime.chevallier@bootlin.com>
---
 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-connector.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_
 
 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	:= netlink.o bitset.o strset.o linkinfo.o linkmodes.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] = {
 	[ETHTOOL_MSG_TSCONFIG_SET]	= &ethnl_tsconfig_request_ops,
 	[ETHTOOL_MSG_PHY_GET]		= &ethnl_phy_request_ops,
 	[ETHTOOL_MSG_MSE_GET]		= &ethnl_mse_request_ops,
+	[ETHTOOL_MSG_PORT_GET]		= &ethnl_port_request_ops,
 };
 
 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
@@ -1544,6 +1545,16 @@ static const struct genl_ops ethtool_genl_ops[] = {
 		.policy = ethnl_mse_get_policy,
 		.maxattr = ARRAY_SIZE(ethnl_mse_get_policy) - 1,
 	},
+	{
+		.cmd	= ETHTOOL_MSG_PORT_GET,
+		.doit	= ethnl_default_doit,
+		.start	= ethnl_port_dump_start,
+		.dumpit	= ethnl_port_dumpit,
+		.done	= ethnl_port_dump_done,
+		.policy = ethnl_port_get_policy,
+		.maxattr = ARRAY_SIZE(ethnl_port_get_policy) - 1,
+	},
+
 };
 
 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
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;
 
 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[ETHTOOL_A_PHY_HEADER + 1];
 extern const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEADER + 1];
 extern const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_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];
 
 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 netlink_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);
 
 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_GSTRING_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 <linux/phy.h>
+#include <linux/phy_link_topology.h>
+#include <linux/phy_port.h>
+#include <net/netdev_lock.h>
+
+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] = {
+	[ETHTOOL_A_PORT_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
+	[ETHTOOL_A_PORT_ID] = { .type = 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 = PORT_REQINFO(req_info);
+
+	/* PORT id is required for GET requests */
+	if (tb[ETHTOOL_A_PORT_ID])
+		request->port_id = 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 = PORT_REPDATA(reply_data);
+	struct port_req_info *request = 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 = 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 = port->id;
+	reply->mii = port->is_mii;
+	reply->sfp = port->is_sfp;
+	reply->occupied = 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 = req_info->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
+	struct port_reply_data *reply = PORT_REPDATA(reply_data);
+	size_t size = 0;
+	int ret;
+
+	/* ETHTOOL_A_PORT_ID */
+	size += nla_total_size(sizeof(u32));
+
+	if (!reply->mii) {
+		/* ETHTOOL_A_PORT_SUPPORTED_MODES */
+		ret = ethnl_bitset_size(reply->supported, NULL,
+					__ETHTOOL_LINK_MODE_MASK_NBITS,
+					link_mode_names, compact);
+		if (ret < 0)
+			return ret;
+
+		size += ret;
+	} else {
+		/* ETHTOOL_A_PORT_SUPPORTED_INTERFACES */
+		ret = ethnl_bitset_size(reply->interfaces, NULL,
+					PHY_INTERFACE_MODE_MAX,
+					phy_interface_names, compact);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* ETHTOOL_A_PORT_TYPE */
+	size += nla_total_size(sizeof(u8));
+
+	/* ETHTOOL_A_PORT_OCCUPIED */
+	size += 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 = req_info->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
+	struct port_reply_data *reply = PORT_REPDATA(reply_data);
+	int ret, port_type = ETHTOOL_PORT_TYPE_MDI;
+
+	if (nla_put_u32(skb, ETHTOOL_A_PORT_ID, reply->port_id))
+		return -EMSGSIZE;
+
+	if (!reply->mii) {
+		ret = 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 = 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 = 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 = genl_dumpit_info(cb);
+	struct port_dump_ctx *ctx = port_dump_ctx_get(cb);
+	struct nlattr **tb = 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 = kzalloc(sizeof(*req_info), GFP_KERNEL);
+	if (!req_info)
+		return -ENOMEM;
+
+	reply_data = kmalloc(sizeof(*reply_data), GFP_KERNEL);
+	if (!reply_data) {
+		ret = -ENOMEM;
+		goto free_req_info;
+	}
+
+	ret = ethnl_parse_header_dev_get(&req_info->base, tb[ETHTOOL_A_PORT_HEADER],
+					 genl_info_net(&info->info),
+					 info->info.extack, false);
+	if (ret < 0)
+		return ret;
+
+	ctx->ifindex = 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 = req_info->base.dev->ifindex;
+		netdev_put(req_info->base.dev, &req_info->base.dev_tracker);
+		req_info->base.dev = NULL;
+	}
+
+	ctx->req_info = req_info;
+	ctx->reply_data = 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 = port_dump_ctx_get(cb);
+	void *ehdr;
+	int ret;
+
+	ehdr = 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 = dev;
+
+	rtnl_lock();
+	netdev_lock_ops(dev);
+
+	ret = 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 = ethnl_fill_reply_header(skb, dev, ETHTOOL_A_PORT_HEADER);
+	if (ret < 0)
+		goto out;
+
+	ret = port_fill_reply(skb, &ctx->req_info->base, &ctx->reply_data->base);
+
+out:
+	ctx->reply_data->base.dev = 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 = port_dump_ctx_get(cb);
+	struct net_device *dev;
+	struct phy_port *port;
+	int ret;
+
+	dev = 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 = ctx->pos_portid;
+
+		ret = port_dump_one(skb, dev, cb);
+		if (ret)
+			return ret;
+	}
+
+	ctx->pos_portid = 0;
+
+	return 0;
+}
+
+static int port_dump_all_dev(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct port_dump_ctx *ctx = port_dump_ctx_get(cb);
+	struct net *net = sock_net(skb->sk);
+	netdevice_tracker dev_tracker;
+	struct net_device *dev;
+	int ret = 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 = dev;
+		ret = port_dump_one_dev(skb, cb);
+
+		rcu_read_lock();
+		netdev_put(dev, &dev_tracker);
+		ctx->req_info->base.dev = NULL;
+
+		if (ret < 0 && ret != -EOPNOTSUPP) {
+			if (likely(skb->len))
+				ret = skb->len;
+			break;
+		}
+		ret = 0;
+	}
+	rcu_read_unlock();
+
+	return ret;
+}
+
+int ethnl_port_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
+	struct port_dump_ctx *ctx = port_dump_ctx_get(cb);
+	int ret = 0;
+
+	if (ctx->ifindex) {
+		netdevice_tracker dev_tracker;
+		struct net_device *dev;
+
+		dev = netdev_get_by_index(genl_info_net(&info->info),
+					  ctx->ifindex, &dev_tracker,
+					  GFP_KERNEL);
+		if (!dev)
+			return -ENODEV;
+
+		ctx->req_info->base.dev = dev;
+		ret = port_dump_one_dev(skb, cb);
+		if (ret < 0 && ret != -EOPNOTSUPP && likely(skb->len))
+			ret = skb->len;
+
+		netdev_put(dev, &dev_tracker);
+	} else {
+		ret = port_dump_all_dev(skb, cb);
+	}
+
+	return ret;
+}
+
+int ethnl_port_dump_done(struct netlink_callback *cb)
+{
+	struct port_dump_ctx *ctx = port_dump_ctx_get(cb);
+
+	kfree(ctx->req_info);
+	kfree(ctx->reply_data);
+
+	return 0;
+}
+
+const struct ethnl_request_ops ethnl_port_request_ops = {
+	.request_cmd		= ETHTOOL_MSG_PORT_GET,
+	.reply_cmd		= ETHTOOL_MSG_PORT_GET_REPLY,
+	.hdr_attr		= ETHTOOL_A_PORT_HEADER,
+	.req_info_size		= sizeof(struct port_req_info),
+	.reply_data_size	= sizeof(struct port_reply_data),
+
+	.parse_request		= port_parse_request,
+	.prepare_data		= port_prepare_data,
+	.reply_size		= port_reply_size,
+	.fill_reply		= port_fill_reply,
+};
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 01/13] net: phy: phy_port: Correctly recompute the port's linkmodes
  2026-01-27 13:41 ` [PATCH net-next 01/13] net: phy: phy_port: Correctly recompute the port's linkmodes Maxime Chevallier
@ 2026-01-27 14:00   ` Kory Maincent
  2026-01-27 15:21     ` Maxime Chevallier
  0 siblings, 1 reply; 34+ messages in thread
From: Kory Maincent @ 2026-01-27 14:00 UTC (permalink / raw)
  To: Maxime Chevallier
  Cc: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit, netdev, linux-kernel,
	thomas.petazzoni, Christophe Leroy, Herve Codina,
	Florian Fainelli, Vladimir Oltean, Marek Behún,
	Oleksij Rempel, Nicolò Veronese, Simon Horman, mwojtas,
	Romain Gantois, Daniel Golle, Dimitri Fedrau

On Tue, 27 Jan 2026 14:41:49 +0100
Maxime Chevallier <maxime.chevallier@bootlin.com> wrote:

> 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

Typo here:           ^^^^^^^^^

> 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 <maxime.chevallier@bootlin.com>

It is the only fix of the series, maybe you should send it standalone?
Else this seems ok to me.

-- 
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 01/13] net: phy: phy_port: Correctly recompute the port's linkmodes
  2026-01-27 14:00   ` Kory Maincent
@ 2026-01-27 15:21     ` Maxime Chevallier
  0 siblings, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 15:21 UTC (permalink / raw)
  To: Kory Maincent
  Cc: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit, netdev, linux-kernel,
	thomas.petazzoni, Christophe Leroy, Herve Codina,
	Florian Fainelli, Vladimir Oltean, Marek Behún,
	Oleksij Rempel, Nicolò Veronese, Simon Horman, mwojtas,
	Romain Gantois, Daniel Golle, Dimitri Fedrau



On 27/01/2026 15:00, Kory Maincent wrote:
> On Tue, 27 Jan 2026 14:41:49 +0100
> Maxime Chevallier <maxime.chevallier@bootlin.com> wrote:
> 
>> 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
> 
> Typo here:           ^^^^^^^^^

Erf, thanks :)

> 
>> 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 <maxime.chevallier@bootlin.com>
> 
> It is the only fix of the series, maybe you should send it standalone?
> Else this seems ok to me.
> 

I considered that yeah, however without the rest of this series, this
bug has no impact. I'll probably split it out anyways, depending on how
review goes for the whole series.

Maxime

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing
  2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
                   ` (12 preceding siblings ...)
  2026-01-27 13:42 ` [PATCH net-next 13/13] net: ethtool: Introduce ethtool command to list ports Maxime Chevallier
@ 2026-01-27 21:07 ` Jakub Kicinski
  2026-01-27 21:18   ` Maxime Chevallier
  2026-01-28  8:07   ` Maxime Chevallier
  13 siblings, 2 replies; 34+ messages in thread
From: Jakub Kicinski @ 2026-01-27 21:07 UTC (permalink / raw)
  To: Maxime Chevallier
  Cc: davem, Andrew Lunn, Eric Dumazet, Paolo Abeni, Russell King,
	Heiner Kallweit, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

On Tue, 27 Jan 2026 14:41:48 +0100 Maxime Chevallier wrote:
> This series is another step towards dealing with multi-port interfaces.
> 
> It build on the recent addition of phy_port representation to enable
> listing the front-facing ports of an interface. For now, we don't control
> these ports, we merely list their presence and their capabilities.
> 
> As the most common use-case of multi-port interfaces is combo-ports that
> provide both RJ45 and SFP connectors on a single MAC, there's a lot of
> SFP stuff in this series.
> 
> This series is in 2 main parts. The first one aims at representing the
> SFP cages and modules using phy_port, as combo-ports with RJ45 + SFP are
> by far the most common cases for multi-connector setups.
> 
> The second part is the netlink interface to list those ports, now that
> most use-cases are covered.

Some config-related build unhappines here (kunit hits this):

../include/linux/phy_link_topology.h:110:1: error: return type defaults to ‘int’ [-Wimplicit-int]
  110 | phy_link_topo_get_port(struct net_device *dev, u32 port_id)
      | ^~~~~~~~~~~~~~~~~~~~~~
../include/linux/phy_link_topology.h:110:1: warning: no previous prototype for ‘phy_link_topo_get_port’ [-Wmissing-prototypes]
In file included from ../include/uapi/linux/posix_types.h:5,
                 from ../include/uapi/linux/types.h:14,
                 from ../include/linux/types.h:6,
                 from ../include/linux/kasan-checks.h:5,
                 from ../include/asm-generic/rwonce.h:26,
                 from ./arch/x86/include/generated/asm/rwonce.h:1,
                 from ../include/linux/compiler.h:380,
                 from ../include/linux/build_bug.h:5,
                 from ../include/linux/bits.h:30,
                 from ../include/linux/bitops.h:6,
                 from ../include/linux/bitmap.h:8,
                 from ../include/linux/ethtool.h:16,
                 from ../include/uapi/linux/ethtool_netlink.h:12,
                 from ../include/linux/ethtool_netlink.h:6,
                 from ../net/ethtool/common.c:3:
../include/linux/phy_link_topology.h: In function ‘phy_link_topo_get_port’:
../include/linux/stddef.h:8:14: error: returning ‘void *’ from a function with return type ‘int’ makes integer from pointer without a cast [-Wint-conversion]
    8 | #define NULL ((void *)0)
      |              ^
../include/linux/phy_link_topology.h:112:16: note: in expansion of macro ‘NULL’
  112 |         return NULL;
      |                ^~~~
-- 
pw-bot: cr

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing
  2026-01-27 21:07 ` [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Jakub Kicinski
@ 2026-01-27 21:18   ` Maxime Chevallier
  2026-01-28  8:07   ` Maxime Chevallier
  1 sibling, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-27 21:18 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, Andrew Lunn, Eric Dumazet, Paolo Abeni, Russell King,
	Heiner Kallweit, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

Hi,

On 27/01/2026 22:07, Jakub Kicinski wrote:
> On Tue, 27 Jan 2026 14:41:48 +0100 Maxime Chevallier wrote:
>> This series is another step towards dealing with multi-port interfaces.
>>
>> It build on the recent addition of phy_port representation to enable
>> listing the front-facing ports of an interface. For now, we don't control
>> these ports, we merely list their presence and their capabilities.
>>
>> As the most common use-case of multi-port interfaces is combo-ports that
>> provide both RJ45 and SFP connectors on a single MAC, there's a lot of
>> SFP stuff in this series.
>>
>> This series is in 2 main parts. The first one aims at representing the
>> SFP cages and modules using phy_port, as combo-ports with RJ45 + SFP are
>> by far the most common cases for multi-connector setups.
>>
>> The second part is the netlink interface to list those ports, now that
>> most use-cases are covered.
> 
> Some config-related build unhappines here (kunit hits this):
> 
> ../include/linux/phy_link_topology.h:110:1: error: return type defaults to ‘int’ [-Wimplicit-int]
>   110 | phy_link_topo_get_port(struct net_device *dev, u32 port_id)
>       | ^~~~~~~~~~~~~~~~~~~~~~
> ../include/linux/phy_link_topology.h:110:1: warning: no previous prototype for ‘phy_link_topo_get_port’ [-Wmissing-prototypes]
> In file included from ../include/uapi/linux/posix_types.h:5,
>                  from ../include/uapi/linux/types.h:14,
>                  from ../include/linux/types.h:6,
>                  from ../include/linux/kasan-checks.h:5,
>                  from ../include/asm-generic/rwonce.h:26,
>                  from ./arch/x86/include/generated/asm/rwonce.h:1,
>                  from ../include/linux/compiler.h:380,
>                  from ../include/linux/build_bug.h:5,
>                  from ../include/linux/bits.h:30,
>                  from ../include/linux/bitops.h:6,
>                  from ../include/linux/bitmap.h:8,
>                  from ../include/linux/ethtool.h:16,
>                  from ../include/uapi/linux/ethtool_netlink.h:12,
>                  from ../include/linux/ethtool_netlink.h:6,
>                  from ../net/ethtool/common.c:3:
> ../include/linux/phy_link_topology.h: In function ‘phy_link_topo_get_port’:
> ../include/linux/stddef.h:8:14: error: returning ‘void *’ from a function with return type ‘int’ makes integer from pointer without a cast [-Wint-conversion]
>     8 | #define NULL ((void *)0)
>       |              ^
> ../include/linux/phy_link_topology.h:112:16: note: in expansion of macro ‘NULL’
>   112 |         return NULL;
>       |                ^~~~

Ah yes indeed, silly mistake from me but wasn't caught by running
./ingest_mdir.py locally, I'll increase my local coverage with a
defconfig that triggers this.

I was so focused making sure the various combinations of phylib et.al.
being built as modules or builtin that I didn't test with PHYLIB=n :/

Thanks for reporting, I'll address that :)

Maxime

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports
  2026-01-27 13:41 ` [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports Maxime Chevallier
@ 2026-01-27 22:23   ` kernel test robot
  2026-01-27 22:44   ` kernel test robot
  2026-01-28 16:10   ` Romain Gantois
  2 siblings, 0 replies; 34+ messages in thread
From: kernel test robot @ 2026-01-27 22:23 UTC (permalink / raw)
  To: Maxime Chevallier, davem, Andrew Lunn, Jakub Kicinski,
	Eric Dumazet, Paolo Abeni, Russell King, Heiner Kallweit
  Cc: oe-kbuild-all, Maxime Chevallier, netdev, linux-kernel,
	thomas.petazzoni, Christophe Leroy, Herve Codina,
	Florian Fainelli, Vladimir Oltean, Köry Maincent,
	Marek Behún, Oleksij Rempel, Nicolò Veronese,
	Simon Horman, mwojtas, Romain Gantois, Daniel Golle,
	Dimitri Fedrau

Hi Maxime,

kernel test robot noticed the following build errors:

[auto build test ERROR on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Maxime-Chevallier/net-phy-phy_port-Correctly-recompute-the-port-s-linkmodes/20260127-215318
base:   net-next/main
patch link:    https://lore.kernel.org/r/20260127134202.8208-11-maxime.chevallier%40bootlin.com
patch subject: [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports
config: i386-randconfig-141-20260128 (https://download.01.org/0day-ci/archive/20260128/202601280617.qlkBpNaP-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
smatch version: v0.5.0-8994-gd50c5a4c
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260128/202601280617.qlkBpNaP-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601280617.qlkBpNaP-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from net/core/dev.c:165:
>> include/linux/phy_link_topology.h:110:1: error: return type defaults to 'int' [-Wimplicit-int]
     110 | phy_link_topo_get_port(struct net_device *dev, u32 port_id)
         | ^~~~~~~~~~~~~~~~~~~~~~
   include/linux/phy_link_topology.h:110:1: warning: no previous prototype for 'phy_link_topo_get_port' [-Wmissing-prototypes]
   In file included from include/uapi/linux/posix_types.h:5,
                    from include/uapi/linux/types.h:14,
                    from include/linux/types.h:6,
                    from include/linux/kasan-checks.h:5,
                    from include/asm-generic/rwonce.h:26,
                    from ./arch/x86/include/generated/asm/rwonce.h:1,
                    from include/linux/compiler.h:380,
                    from include/linux/cleanup.h:5,
                    from include/linux/uaccess.h:5,
                    from net/core/dev.c:71:
   include/linux/phy_link_topology.h: In function 'phy_link_topo_get_port':
>> include/linux/stddef.h:8:14: error: returning 'void *' from a function with return type 'int' makes integer from pointer without a cast [-Wint-conversion]
       8 | #define NULL ((void *)0)
         |              ^
   include/linux/phy_link_topology.h:112:16: note: in expansion of macro 'NULL'
     112 |         return NULL;
         |                ^~~~


vim +/int +110 include/linux/phy_link_topology.h

   109	
 > 110	phy_link_topo_get_port(struct net_device *dev, u32 port_id)
   111	{
   112		return NULL;
   113	}
   114	#endif
   115	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports
  2026-01-27 13:41 ` [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports Maxime Chevallier
  2026-01-27 22:23   ` kernel test robot
@ 2026-01-27 22:44   ` kernel test robot
  2026-01-28 16:10   ` Romain Gantois
  2 siblings, 0 replies; 34+ messages in thread
From: kernel test robot @ 2026-01-27 22:44 UTC (permalink / raw)
  To: Maxime Chevallier, davem, Andrew Lunn, Jakub Kicinski,
	Eric Dumazet, Paolo Abeni, Russell King, Heiner Kallweit
  Cc: oe-kbuild-all, Maxime Chevallier, netdev, linux-kernel,
	thomas.petazzoni, Christophe Leroy, Herve Codina,
	Florian Fainelli, Vladimir Oltean, Köry Maincent,
	Marek Behún, Oleksij Rempel, Nicolò Veronese,
	Simon Horman, mwojtas, Romain Gantois, Daniel Golle,
	Dimitri Fedrau

Hi Maxime,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Maxime-Chevallier/net-phy-phy_port-Correctly-recompute-the-port-s-linkmodes/20260127-215318
base:   net-next/main
patch link:    https://lore.kernel.org/r/20260127134202.8208-11-maxime.chevallier%40bootlin.com
patch subject: [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports
config: s390-randconfig-002-20260128 (https://download.01.org/0day-ci/archive/20260128/202601280624.F1IZ2yHm-lkp@intel.com/config)
compiler: s390-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260128/202601280624.F1IZ2yHm-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601280624.F1IZ2yHm-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from net/ethtool/tsinfo.c:5:
   include/linux/phy_link_topology.h:110:1: error: return type defaults to 'int' [-Werror=implicit-int]
    phy_link_topo_get_port(struct net_device *dev, u32 port_id)
    ^~~~~~~~~~~~~~~~~~~~~~
   include/linux/phy_link_topology.h:110:1: warning: no previous prototype for 'phy_link_topo_get_port' [-Wmissing-prototypes]
   In file included from include/uapi/linux/posix_types.h:5,
                    from include/uapi/linux/types.h:14,
                    from include/linux/types.h:6,
                    from include/uapi/linux/net_tstamp.h:13,
                    from include/linux/net_tstamp.h:6,
                    from net/ethtool/tsinfo.c:3:
   include/linux/phy_link_topology.h: In function 'phy_link_topo_get_port':
>> include/linux/stddef.h:8:14: warning: returning 'void *' from a function with return type 'int' makes integer from pointer without a cast [-Wint-conversion]
    #define NULL ((void *)0)
                 ^
   include/linux/phy_link_topology.h:112:9: note: in expansion of macro 'NULL'
     return NULL;
            ^~~~
   cc1: some warnings being treated as errors


vim +8 include/linux/stddef.h

^1da177e4c3f41 Linus Torvalds   2005-04-16  6  
^1da177e4c3f41 Linus Torvalds   2005-04-16  7  #undef NULL
^1da177e4c3f41 Linus Torvalds   2005-04-16 @8  #define NULL ((void *)0)
6e218287432472 Richard Knutsson 2006-09-30  9  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 13/13] net: ethtool: Introduce ethtool command to list ports
  2026-01-27 13:42 ` [PATCH net-next 13/13] net: ethtool: Introduce ethtool command to list ports Maxime Chevallier
@ 2026-01-27 23:16   ` kernel test robot
  0 siblings, 0 replies; 34+ messages in thread
From: kernel test robot @ 2026-01-27 23:16 UTC (permalink / raw)
  To: Maxime Chevallier, davem, Andrew Lunn, Jakub Kicinski,
	Eric Dumazet, Paolo Abeni, Russell King, Heiner Kallweit
  Cc: llvm, oe-kbuild-all, Maxime Chevallier, netdev, linux-kernel,
	thomas.petazzoni, Christophe Leroy, Herve Codina,
	Florian Fainelli, Vladimir Oltean, Köry Maincent,
	Marek Behún, Oleksij Rempel, Nicolò Veronese,
	Simon Horman, mwojtas, Romain Gantois, Daniel Golle,
	Dimitri Fedrau

Hi Maxime,

kernel test robot noticed the following build errors:

[auto build test ERROR on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Maxime-Chevallier/net-phy-phy_port-Correctly-recompute-the-port-s-linkmodes/20260127-215318
base:   net-next/main
patch link:    https://lore.kernel.org/r/20260127134202.8208-14-maxime.chevallier%40bootlin.com
patch subject: [PATCH net-next 13/13] net: ethtool: Introduce ethtool command to list ports
config: um-defconfig (https://download.01.org/0day-ci/archive/20260128/202601280753.G8XBwank-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 9b8addffa70cee5b2acc5454712d9cf78ce45710)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260128/202601280753.G8XBwank-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601280753.G8XBwank-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from net/core/dev.c:165:
>> include/linux/phy_link_topology.h:110:1: error: type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int [-Wimplicit-int]
     110 | phy_link_topo_get_port(struct net_device *dev, u32 port_id)
         | ^
         | int
>> include/linux/phy_link_topology.h:112:9: error: incompatible pointer to integer conversion returning 'void *' from a function with result type 'int' [-Wint-conversion]
     112 |         return NULL;
         |                ^~~~
   include/linux/stddef.h:8:14: note: expanded from macro 'NULL'
       8 | #define NULL ((void *)0)
         |              ^~~~~~~~~~~
   In file included from net/core/dev.c:165:
   include/linux/phy_link_topology.h:110:1: warning: no previous prototype for function 'phy_link_topo_get_port' [-Wmissing-prototypes]
     110 | phy_link_topo_get_port(struct net_device *dev, u32 port_id)
         | ^
   include/linux/phy_link_topology.h:110:23: note: declare 'static' if the function is not intended to be used outside of this translation unit
     110 | phy_link_topo_get_port(struct net_device *dev, u32 port_id)
         |                       ^
         |                       static 
   1 warning and 2 errors generated.
--
   In file included from net/ethtool/port.c:11:
>> include/linux/phy_link_topology.h:110:1: error: type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int [-Wimplicit-int]
     110 | phy_link_topo_get_port(struct net_device *dev, u32 port_id)
         | ^
         | int
>> include/linux/phy_link_topology.h:112:9: error: incompatible pointer to integer conversion returning 'void *' from a function with result type 'int' [-Wint-conversion]
     112 |         return NULL;
         |                ^~~~
   include/linux/stddef.h:8:14: note: expanded from macro 'NULL'
       8 | #define NULL ((void *)0)
         |              ^~~~~~~~~~~
   In file included from net/ethtool/port.c:11:
   include/linux/phy_link_topology.h:110:1: warning: no previous prototype for function 'phy_link_topo_get_port' [-Wmissing-prototypes]
     110 | phy_link_topo_get_port(struct net_device *dev, u32 port_id)
         | ^
   include/linux/phy_link_topology.h:110:23: note: declare 'static' if the function is not intended to be used outside of this translation unit
     110 | phy_link_topo_get_port(struct net_device *dev, u32 port_id)
         |                       ^
         |                       static 
>> net/ethtool/port.c:70:7: error: incompatible integer to pointer conversion assigning to 'struct phy_port *' from 'int' [-Wint-conversion]
      70 |         port = phy_link_topo_get_port(req_info->dev, request->port_id);
         |              ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   1 warning and 3 errors generated.


vim +/int +110 include/linux/phy_link_topology.h

624ef6af11779e Maxime Chevallier 2026-01-27  109  
624ef6af11779e Maxime Chevallier 2026-01-27 @110  phy_link_topo_get_port(struct net_device *dev, u32 port_id)
624ef6af11779e Maxime Chevallier 2026-01-27  111  {
624ef6af11779e Maxime Chevallier 2026-01-27 @112  	return NULL;
624ef6af11779e Maxime Chevallier 2026-01-27  113  }
38496878690920 Maxime Chevallier 2024-08-21  114  #endif
38496878690920 Maxime Chevallier 2024-08-21  115  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing
  2026-01-27 21:07 ` [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Jakub Kicinski
  2026-01-27 21:18   ` Maxime Chevallier
@ 2026-01-28  8:07   ` Maxime Chevallier
  1 sibling, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-28  8:07 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, Andrew Lunn, Eric Dumazet, Paolo Abeni, Russell King,
	Heiner Kallweit, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

Hi again,

On 27/01/2026 22:07, Jakub Kicinski wrote:

> Some config-related build unhappines here (kunit hits this):
> 
> ../include/linux/phy_link_topology.h:110:1: error: return type defaults to ‘int’ [-Wimplicit-int]
>   110 | phy_link_topo_get_port(struct net_device *dev, u32 port_id)
>       | ^~~~~~~~~~~~~~~~~~~~~~
> ../include/linux/phy_link_topology.h:110:1: warning: no previous prototype for ‘phy_link_topo_get_port’ [-Wmissing-prototypes]
> In file included from ../include/uapi/linux/posix_types.h:5,
>                  from ../include/uapi/linux/types.h:14,
>                  from ../include/linux/types.h:6,
>                  from ../include/linux/kasan-checks.h:5,
>                  from ../include/asm-generic/rwonce.h:26,
>                  from ./arch/x86/include/generated/asm/rwonce.h:1,
>                  from ../include/linux/compiler.h:380,
>                  from ../include/linux/build_bug.h:5,
>                  from ../include/linux/bits.h:30,
>                  from ../include/linux/bitops.h:6,
>                  from ../include/linux/bitmap.h:8,
>                  from ../include/linux/ethtool.h:16,
>                  from ../include/uapi/linux/ethtool_netlink.h:12,
>                  from ../include/linux/ethtool_netlink.h:6,
>                  from ../net/ethtool/common.c:3:
> ../include/linux/phy_link_topology.h: In function ‘phy_link_topo_get_port’:
> ../include/linux/stddef.h:8:14: error: returning ‘void *’ from a function with return type ‘int’ makes integer from pointer without a cast [-Wint-conversion]
>     8 | #define NULL ((void *)0)
>       |              ^
> ../include/linux/phy_link_topology.h:112:16: note: in expansion of macro ‘NULL’
>   112 |         return NULL;
>       |                ^~~~

The kernel test bot also found it, and AI found stuff to fix I'll
address that + AI review then :)

Maxime

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 05/13] net: phy: Create SFP phy_port before registering usptream
  2026-01-27 13:41 ` [PATCH net-next 05/13] net: phy: Create SFP phy_port before registering usptream Maxime Chevallier
@ 2026-01-28 15:49   ` Romain Gantois
  2026-01-30 13:31     ` Maxime Chevallier
  0 siblings, 1 reply; 34+ messages in thread
From: Romain Gantois @ 2026-01-28 15:49 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit, Maxime Chevallier
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Daniel Golle,
	Dimitri Fedrau

[-- Attachment #1: Type: text/plain, Size: 335 bytes --]

Hi Maxime,

On Tuesday, 27 January 2026 14:41:53 CET Maxime Chevallier wrote:
> When dealing with PHY-driver SFP, we create a phy_port representing the
> SFP bus when we know we have such a bus.

Shouldn't this be "with a PHY-driven SFP"?

Thanks,

-- 
Romain Gantois, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 07/13] net: phy: Represent PHY-less SFP modules with phy_port
  2026-01-27 13:41 ` [PATCH net-next 07/13] net: phy: Represent PHY-less SFP modules with phy_port Maxime Chevallier
@ 2026-01-28 15:54   ` Romain Gantois
  2026-01-30 13:32     ` Maxime Chevallier
  0 siblings, 1 reply; 34+ messages in thread
From: Romain Gantois @ 2026-01-28 15:54 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit, Maxime Chevallier
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Daniel Golle,
	Dimitri Fedrau

[-- Attachment #1: Type: text/plain, Size: 653 bytes --]

On Tuesday, 27 January 2026 14:41:55 CET Maxime Chevallier wrote:
> Now that th SFP bus infrastructure notifies when PHY-less modules are

There's a typo here.

> 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

Alongside what?

Thanks,

-- 
Romain Gantois, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 08/13] net: phylink: Represent PHY-less SFP modules with phy_port
  2026-01-27 13:41 ` [PATCH net-next 08/13] net: phylink: " Maxime Chevallier
@ 2026-01-28 16:01   ` Romain Gantois
  2026-01-30 13:36     ` Maxime Chevallier
  0 siblings, 1 reply; 34+ messages in thread
From: Romain Gantois @ 2026-01-28 16:01 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit, Maxime Chevallier
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Daniel Golle,
	Dimitri Fedrau

[-- Attachment #1: Type: text/plain, Size: 1577 bytes --]

On Tuesday, 27 January 2026 14:41:56 CET Maxime Chevallier wrote:
...
> @@ -1786,13 +1787,31 @@ static int phylink_create_sfp_port(struct phylink
> *pl) else
> 
>  		pl->sfp_bus_port = port;
> 
> +	if (pl->mod_port) {
> +		ret = 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);

This seems strange to me. Why clean up after phy_link_topo_add_port() if it 
returned an error code? Presumably phy_link_topo_add_port() cleans up after 
itself if it encounters an error doesn't it?

> +	phy_port_destroy(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->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);
> +	}
> 
>  	if (pl->sfp_bus_port)
>  	
>  		phy_port_destroy(pl->sfp_bus_port);
> 
> @@ -3998,6 +4017,49 @@ static void phylink_sfp_disconnect_phy(void
> *upstream, phylink_disconnect_phy(upstream);
> 
>  }
> 
> +static int phylink_sfp_connect_nophy(void *upstream)

I'd name this "phylink_sfp_connect_no_phy" just to keep the name formatting 
consistent.

Thanks,

-- 
Romain Gantois, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 09/13] net: phy: phy_port: Store information about a MII port's occupancy
  2026-01-27 13:41 ` [PATCH net-next 09/13] net: phy: phy_port: Store information about a MII port's occupancy Maxime Chevallier
@ 2026-01-28 16:08   ` Romain Gantois
  2026-01-30 13:38     ` Maxime Chevallier
  0 siblings, 1 reply; 34+ messages in thread
From: Romain Gantois @ 2026-01-28 16:08 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit, Maxime Chevallier
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Daniel Golle,
	Dimitri Fedrau

[-- Attachment #1: Type: text/plain, Size: 991 bytes --]

On Tuesday, 27 January 2026 14:41:57 CET Maxime Chevallier wrote:
> 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).

To me, "front-facing" refers to things like user ports on a switch versus CPU-
facing ports, I don't find it intuitive to use it to qualify a port's state of 
being connected to an empty SFP cage.

Why not use something like "vacant" or "empty" instead?

Thanks,

-- 
Romain Gantois, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports
  2026-01-27 13:41 ` [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports Maxime Chevallier
  2026-01-27 22:23   ` kernel test robot
  2026-01-27 22:44   ` kernel test robot
@ 2026-01-28 16:10   ` Romain Gantois
  2026-01-30 13:41     ` Maxime Chevallier
  2 siblings, 1 reply; 34+ messages in thread
From: Romain Gantois @ 2026-01-28 16:10 UTC (permalink / raw)
  To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Russell King, Heiner Kallweit, Maxime Chevallier
  Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Daniel Golle,
	Dimitri Fedrau

[-- Attachment #1: Type: text/plain, Size: 430 bytes --]

On Tuesday, 27 January 2026 14:41:58 CET Maxime Chevallier wrote:
> 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.

Why not use rtnl-specific lockdep annotations to make this more explicit?

Thanks,

-- 
Romain Gantois, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 05/13] net: phy: Create SFP phy_port before registering usptream
  2026-01-28 15:49   ` Romain Gantois
@ 2026-01-30 13:31     ` Maxime Chevallier
  0 siblings, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-30 13:31 UTC (permalink / raw)
  To: Romain Gantois, davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
	Paolo Abeni, Russell King, Heiner Kallweit
  Cc: netdev, linux-kernel, thomas.petazzoni, Christophe Leroy,
	Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Daniel Golle,
	Dimitri Fedrau

Hi Romain,

Sorry I missed these when sending V2, I'll integrate in v3.

On 28/01/2026 16:49, Romain Gantois wrote:
> Hi Maxime,
> 
> On Tuesday, 27 January 2026 14:41:53 CET Maxime Chevallier wrote:
>> When dealing with PHY-driver SFP, we create a phy_port representing the
>> SFP bus when we know we have such a bus.
> 
> Shouldn't this be "with a PHY-driven SFP"?

indeed,

Thanks,

Maxime

> 
> Thanks,
> 


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 07/13] net: phy: Represent PHY-less SFP modules with phy_port
  2026-01-28 15:54   ` Romain Gantois
@ 2026-01-30 13:32     ` Maxime Chevallier
  0 siblings, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-30 13:32 UTC (permalink / raw)
  To: Romain Gantois, davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
	Paolo Abeni, Russell King, Heiner Kallweit
  Cc: netdev, linux-kernel, thomas.petazzoni, Christophe Leroy,
	Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Daniel Golle,
	Dimitri Fedrau



On 28/01/2026 16:54, Romain Gantois wrote:
> On Tuesday, 27 January 2026 14:41:55 CET Maxime Chevallier wrote:
>> Now that th SFP bus infrastructure notifies when PHY-less modules are
> 
> There's a typo here.

Ack

> 
>> 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
> 
> Alongside what?

Alongside this patch ?

I'll reword.

Maxime

> 
> Thanks,
> 


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 08/13] net: phylink: Represent PHY-less SFP modules with phy_port
  2026-01-28 16:01   ` Romain Gantois
@ 2026-01-30 13:36     ` Maxime Chevallier
  0 siblings, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-30 13:36 UTC (permalink / raw)
  To: Romain Gantois, davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
	Paolo Abeni, Russell King, Heiner Kallweit
  Cc: netdev, linux-kernel, thomas.petazzoni, Christophe Leroy,
	Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Daniel Golle,
	Dimitri Fedrau



On 28/01/2026 17:01, Romain Gantois wrote:
> On Tuesday, 27 January 2026 14:41:56 CET Maxime Chevallier wrote:
> ...
>> @@ -1786,13 +1787,31 @@ static int phylink_create_sfp_port(struct phylink
>> *pl) else
>>
>>  		pl->sfp_bus_port = port;
>>
>> +	if (pl->mod_port) {
>> +		ret = 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);
> 
> This seems strange to me. Why clean up after phy_link_topo_add_port() if it 
> returned an error code? Presumably phy_link_topo_add_port() cleans up after 
> itself if it encounters an error doesn't it?

Because we're not cleaning up the same port, notice the 'port' vs
'pl->mod_port' params :)

> 
>> +	phy_port_destroy(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->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);
>> +	}
>>
>>  	if (pl->sfp_bus_port)
>>  	
>>  		phy_port_destroy(pl->sfp_bus_port);
>>
>> @@ -3998,6 +4017,49 @@ static void phylink_sfp_disconnect_phy(void
>> *upstream, phylink_disconnect_phy(upstream);
>>
>>  }
>>
>> +static int phylink_sfp_connect_nophy(void *upstream)
> 
> I'd name this "phylink_sfp_connect_no_phy" just to keep the name formatting 
> consistent.

having 'nophy' as a single word made it clearer that this was "phy" vs
"nophy" IMO, rather than potentially interpreting "phy" as a suffix. but
I see your point, I think I'll rename it :)

Maxime

> 
> Thanks,
> 


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 09/13] net: phy: phy_port: Store information about a MII port's occupancy
  2026-01-28 16:08   ` Romain Gantois
@ 2026-01-30 13:38     ` Maxime Chevallier
  0 siblings, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-30 13:38 UTC (permalink / raw)
  To: Romain Gantois, davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
	Paolo Abeni, Russell King, Heiner Kallweit
  Cc: netdev, linux-kernel, thomas.petazzoni, Christophe Leroy,
	Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Daniel Golle,
	Dimitri Fedrau



On 28/01/2026 17:08, Romain Gantois wrote:
> On Tuesday, 27 January 2026 14:41:57 CET Maxime Chevallier wrote:
>> 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).
> 
> To me, "front-facing" refers to things like user ports on a switch versus CPU-
> facing ports, I don't find it intuitive to use it to qualify a port's state of 
> being connected to an empty SFP cage.
> 
> Why not use something like "vacant" or "empty" instead?

ah 'vacant' was the term I was looking for !

OK I'll update, I like that better :)

Maxime

> 
> Thanks,
> 


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports
  2026-01-28 16:10   ` Romain Gantois
@ 2026-01-30 13:41     ` Maxime Chevallier
  0 siblings, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-30 13:41 UTC (permalink / raw)
  To: Romain Gantois, davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet,
	Paolo Abeni, Russell King, Heiner Kallweit
  Cc: netdev, linux-kernel, thomas.petazzoni, Christophe Leroy,
	Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Daniel Golle,
	Dimitri Fedrau



On 28/01/2026 17:10, Romain Gantois wrote:
> On Tuesday, 27 January 2026 14:41:58 CET Maxime Chevallier wrote:
>> 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.
> 
> Why not use rtnl-specific lockdep annotations to make this more explicit?

While this makes sure the call-site holds the lock as it should, it
doesn't guarantee the caller won't release it too early.

Doesn't hurt to add it though :)

Maxime

> 
> Thanks,
> 


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 06/13] net: sfp: Add a sfp-bus ops when connecting a module without PHY
  2026-01-27 13:41 ` [PATCH net-next 06/13] net: sfp: Add a sfp-bus ops when connecting a module without PHY Maxime Chevallier
@ 2026-01-30 16:19   ` Russell King (Oracle)
  2026-01-30 17:08     ` Maxime Chevallier
  0 siblings, 1 reply; 34+ messages in thread
From: Russell King (Oracle) @ 2026-01-30 16:19 UTC (permalink / raw)
  To: Maxime Chevallier
  Cc: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Heiner Kallweit, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

On Tue, Jan 27, 2026 at 02:41:54PM +0100, Maxime Chevallier wrote:
> 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.

That's the way you tell - if you get the .start() callback but you
haven't had a PHY connected, that means there's no PHY.

There should be no need to add this callback, since you shouldn't be
thinking that the module is fully initialised until you have received
the .start() callback.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH net-next 06/13] net: sfp: Add a sfp-bus ops when connecting a module without PHY
  2026-01-30 16:19   ` Russell King (Oracle)
@ 2026-01-30 17:08     ` Maxime Chevallier
  0 siblings, 0 replies; 34+ messages in thread
From: Maxime Chevallier @ 2026-01-30 17:08 UTC (permalink / raw)
  To: Russell King (Oracle)
  Cc: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
	Heiner Kallweit, netdev, linux-kernel, thomas.petazzoni,
	Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
	Köry Maincent, Marek Behún, Oleksij Rempel,
	Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
	Daniel Golle, Dimitri Fedrau

Hi Russell,

On 30/01/2026 17:19, Russell King (Oracle) wrote:
> On Tue, Jan 27, 2026 at 02:41:54PM +0100, Maxime Chevallier wrote:
>> 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.
> 
> That's the way you tell - if you get the .start() callback but you
> haven't had a PHY connected, that means there's no PHY.
> 
> There should be no need to add this callback, since you shouldn't be
> thinking that the module is fully initialised until you have received
> the .start() callback.
> 

Ok fair point, thanks for the feedback ! I was about to send V3, but
I'll implement something that doesn't require this new callback then.

Thanks for taking a look :)

Maxime

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2026-01-30 17:08 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-27 13:41 [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
2026-01-27 13:41 ` [PATCH net-next 01/13] net: phy: phy_port: Correctly recompute the port's linkmodes Maxime Chevallier
2026-01-27 14:00   ` Kory Maincent
2026-01-27 15:21     ` Maxime Chevallier
2026-01-27 13:41 ` [PATCH net-next 02/13] net: phy: phy_link_topology: Add a helper for opportunistic alloc Maxime Chevallier
2026-01-27 13:41 ` [PATCH net-next 03/13] net: phy: phy_link_topology: Track ports in phy_link_topology Maxime Chevallier
2026-01-27 13:41 ` [PATCH net-next 04/13] net: phylink: Register a phy_port for MAC-driven SFP busses Maxime Chevallier
2026-01-27 13:41 ` [PATCH net-next 05/13] net: phy: Create SFP phy_port before registering usptream Maxime Chevallier
2026-01-28 15:49   ` Romain Gantois
2026-01-30 13:31     ` Maxime Chevallier
2026-01-27 13:41 ` [PATCH net-next 06/13] net: sfp: Add a sfp-bus ops when connecting a module without PHY Maxime Chevallier
2026-01-30 16:19   ` Russell King (Oracle)
2026-01-30 17:08     ` Maxime Chevallier
2026-01-27 13:41 ` [PATCH net-next 07/13] net: phy: Represent PHY-less SFP modules with phy_port Maxime Chevallier
2026-01-28 15:54   ` Romain Gantois
2026-01-30 13:32     ` Maxime Chevallier
2026-01-27 13:41 ` [PATCH net-next 08/13] net: phylink: " Maxime Chevallier
2026-01-28 16:01   ` Romain Gantois
2026-01-30 13:36     ` Maxime Chevallier
2026-01-27 13:41 ` [PATCH net-next 09/13] net: phy: phy_port: Store information about a MII port's occupancy Maxime Chevallier
2026-01-28 16:08   ` Romain Gantois
2026-01-30 13:38     ` Maxime Chevallier
2026-01-27 13:41 ` [PATCH net-next 10/13] net: phy: phy_link_topology: Add a helper to retrieve ports Maxime Chevallier
2026-01-27 22:23   ` kernel test robot
2026-01-27 22:44   ` kernel test robot
2026-01-28 16:10   ` Romain Gantois
2026-01-30 13:41     ` Maxime Chevallier
2026-01-27 13:41 ` [PATCH net-next 11/13] net: phy: store phy_modes in a static array Maxime Chevallier
2026-01-27 13:42 ` [PATCH net-next 12/13] netlink: specs: Add ethernet port listing with ethtool Maxime Chevallier
2026-01-27 13:42 ` [PATCH net-next 13/13] net: ethtool: Introduce ethtool command to list ports Maxime Chevallier
2026-01-27 23:16   ` kernel test robot
2026-01-27 21:07 ` [PATCH net-next 00/13] net: phy_port: SFP modules representation and phy_port listing Jakub Kicinski
2026-01-27 21:18   ` Maxime Chevallier
2026-01-28  8:07   ` Maxime Chevallier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox