* [PATCH net-next v17 01/10] net: phy: phy_link_topology: Add a helper for opportunistic alloc
2026-09-09 9:39 [PATCH net-next v17 00/10] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
@ 2026-09-09 9:39 ` Maxime Chevallier
2026-09-09 9:39 ` [PATCH net-next v17 02/10] net: phy: phy_link_topology: Track ports in phy_link_topology Maxime Chevallier
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Maxime Chevallier @ 2026-09-09 9:39 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, Frank Wunderlich,
Pietro Ameruoso
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.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/phy_link_topology.c | 40 +++++++++++++++++++++++------
1 file changed, 32 insertions(+), 8 deletions(-)
diff --git a/drivers/net/phy/phy_link_topology.c b/drivers/net/phy/phy_link_topology.c
index 4134de7ae313..0462283c8020 100644
--- a/drivers/net/phy/phy_link_topology.c
+++ b/drivers/net/phy/phy_link_topology.c
@@ -28,11 +28,39 @@ 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. It can be called on multiple
+ * contexts:
+ * - It can be called from .probe() : No rtnl, no netdev_lock
+ * - .ndo_open() : rtnl and possibly netdev_lock
+ * - SFP state machine : rtnl held or not
+ *
+ * However, we can't really have races :
+ * - If we have a PHY, phy_link_topo_add_phy() will always run first
+ * and trigger the alloc. Only then the ports can be added through
+ * phylib or sfp.
+ * - If we don't, the SFP port for the cage is registered first, and
+ * only then other ports/PHYs can be registered.
+ */
+ 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;
@@ -45,13 +73,9 @@ int phy_link_topo_add_phy(struct net_device *dev,
if (WARN_ON_ONCE(netdev_need_ops_lock(dev)))
return -EOPNOTSUPP;
- 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_obj(*pdn);
if (!pdn)
--
2.55.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH net-next v17 02/10] net: phy: phy_link_topology: Track ports in phy_link_topology
2026-09-09 9:39 [PATCH net-next v17 00/10] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
2026-09-09 9:39 ` [PATCH net-next v17 01/10] net: phy: phy_link_topology: Add a helper for opportunistic alloc Maxime Chevallier
@ 2026-09-09 9:39 ` Maxime Chevallier
2026-09-09 9:39 ` [PATCH net-next v17 03/10] net: phylink: Register a phy_port for MAC-driven SFP cages Maxime Chevallier
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Maxime Chevallier @ 2026-09-09 9:39 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, Frank Wunderlich,
Pietro Ameruoso
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.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/phy_device.c | 3 ++
drivers/net/phy/phy_link_topology.c | 53 +++++++++++++++++++++++++++++
include/linux/phy_link_topology.h | 18 ++++++++++
include/linux/phy_port.h | 2 ++
net/core/dev.c | 1 +
5 files changed, 77 insertions(+)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 41d1b20cde2c..2d0fa3c7f18e 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1670,6 +1670,9 @@ static void phy_del_port(struct phy_device *phydev, struct phy_port *port)
list_del(&port->head);
+ if (phydev->attached_dev)
+ phy_link_topo_del_port(phydev->attached_dev, port);
+
phydev->n_ports--;
}
diff --git a/drivers/net/phy/phy_link_topology.c b/drivers/net/phy/phy_link_topology.c
index 0462283c8020..28c5bf3a8849 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>
@@ -23,6 +24,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;
@@ -56,12 +60,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 < 0 ? ret : 0;
+}
+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;
/* ethtool ops may run without rtnl_lock, and rtnl_lock is what
@@ -110,8 +147,20 @@ 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_continue_reverse(port, &phy->ports, head)
+ phy_link_topo_del_port(dev, port);
+
+ xa_erase(&topo->phys, phy->phyindex);
err:
kfree(pdn);
return ret;
@@ -123,10 +172,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 95575f68d5bc..296ee514ba46 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 {
@@ -48,6 +52,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)
{
@@ -77,6 +84,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 {
diff --git a/net/core/dev.c b/net/core/dev.c
index 290e0f099e6b..8c061df5b6a8 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -11367,6 +11367,7 @@ static void netdev_free_phy_link_topology(struct net_device *dev)
if (IS_ENABLED(CONFIG_PHYLIB) && topo) {
xa_destroy(&topo->phys);
+ xa_destroy(&topo->ports);
kfree(topo);
dev->link_topo = NULL;
}
--
2.55.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH net-next v17 03/10] net: phylink: Register a phy_port for MAC-driven SFP cages
2026-09-09 9:39 [PATCH net-next v17 00/10] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
2026-09-09 9:39 ` [PATCH net-next v17 01/10] net: phy: phy_link_topology: Add a helper for opportunistic alloc Maxime Chevallier
2026-09-09 9:39 ` [PATCH net-next v17 02/10] net: phy: phy_link_topology: Track ports in phy_link_topology Maxime Chevallier
@ 2026-09-09 9:39 ` Maxime Chevallier
2026-09-09 9:39 ` [PATCH net-next v17 04/10] net: phy: Create SFP phy_port before registering upstream Maxime Chevallier
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Maxime Chevallier @ 2026-09-09 9:39 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, Frank Wunderlich,
Pietro Ameruoso
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 driven 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.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
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 b9fc8599df74..7c6c4243c711 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_cage_port;
struct eee_config eee_cfg;
@@ -1765,6 +1768,46 @@ static void phylink_fixed_poll(struct timer_list *t)
static const struct sfp_upstream_ops sfp_phylink_ops;
+static int phylink_create_sfp_cage_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_cage_port = port;
+
+ return ret;
+}
+
+static void phylink_destroy_sfp_cage_port(struct phylink *pl)
+{
+ if (pl->netdev && pl->sfp_cage_port)
+ phy_link_topo_del_port(pl->netdev, pl->sfp_cage_port);
+
+ if (pl->sfp_cage_port)
+ phy_port_destroy(pl->sfp_cage_port);
+
+ pl->sfp_cage_port = NULL;
+}
+
static int phylink_register_sfp(struct phylink *pl,
const struct fwnode_handle *fwnode)
{
@@ -1782,9 +1825,18 @@ static int phylink_register_sfp(struct phylink *pl,
pl->sfp_bus = bus;
+ ret = phylink_create_sfp_cage_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_cage_port(pl);
+
return ret;
}
@@ -2067,6 +2119,7 @@ EXPORT_SYMBOL_GPL(phylink_create);
void phylink_destroy(struct phylink *pl)
{
sfp_bus_del_upstream(pl->sfp_bus);
+ phylink_destroy_sfp_cage_port(pl);
if (pl->link_gpio)
gpiod_put(pl->link_gpio);
--
2.55.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH net-next v17 04/10] net: phy: Create SFP phy_port before registering upstream
2026-09-09 9:39 [PATCH net-next v17 00/10] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
` (2 preceding siblings ...)
2026-09-09 9:39 ` [PATCH net-next v17 03/10] net: phylink: Register a phy_port for MAC-driven SFP cages Maxime Chevallier
@ 2026-09-09 9:39 ` Maxime Chevallier
2026-09-09 9:39 ` [PATCH net-next v17 06/10] net: phy: phy_port: Store information about a port's upstream Maxime Chevallier
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Maxime Chevallier @ 2026-09-09 9:39 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, Frank Wunderlich,
Pietro Ameruoso
When dealing with PHY-driven 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.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/phy_device.c | 58 +++++++++++++++++++++++-------------
1 file changed, 38 insertions(+), 20 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 2d0fa3c7f18e..f15c0fc339b4 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1676,13 +1676,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;
@@ -1697,10 +1697,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;
}
/**
@@ -1709,30 +1711,46 @@ static int phy_setup_sfp_port(struct phy_device *phydev)
*/
static int phy_sfp_probe(struct phy_device *phydev)
{
+ struct phy_port *port = NULL;
struct sfp_bus *bus;
- int ret = 0;
+ int ret;
- if (phydev->mdio.dev.fwnode) {
- bus = sfp_bus_find_fwnode(phydev->mdio.dev.fwnode);
- if (IS_ERR(bus))
- return PTR_ERR(bus);
+ if (!phydev->mdio.dev.fwnode)
+ return 0;
- phydev->sfp_bus = bus;
+ bus = sfp_bus_find_fwnode(phydev->mdio.dev.fwnode);
+ if (IS_ERR(bus))
+ return PTR_ERR(bus);
- ret = sfp_bus_add_upstream(bus, phydev, &sfp_phydev_ops);
- sfp_bus_put(bus);
+ phydev->sfp_bus = bus;
- if (ret)
- phydev->sfp_bus = NULL;
+ if (bus) {
+ port = phy_setup_sfp_port(phydev);
+ if (IS_ERR(port)) {
+ ret = PTR_ERR(port);
+ goto out_sfp;
+ }
}
- if (!ret && phydev->sfp_bus) {
- ret = phy_setup_sfp_port(phydev);
- if (ret) {
- sfp_bus_del_upstream(phydev->sfp_bus);
- phydev->sfp_bus = NULL;
- }
+ ret = sfp_bus_add_upstream(bus, phydev, &sfp_phydev_ops);
+ if (ret)
+ goto out_port;
+
+ /* sfp_bus_add_upstream() grabs a ref to the sfp bus on success, it's
+ * safe to release it now.
+ */
+ sfp_bus_put(bus);
+
+ return ret;
+
+out_port:
+ if (port) {
+ phy_del_port(phydev, port);
+ phy_port_destroy(port);
}
+out_sfp:
+ sfp_bus_put(bus);
+ phydev->sfp_bus = NULL;
return ret;
}
--
2.55.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH net-next v17 06/10] net: phy: phy_port: Store information about a port's upstream
2026-09-09 9:39 [PATCH net-next v17 00/10] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
` (3 preceding siblings ...)
2026-09-09 9:39 ` [PATCH net-next v17 04/10] net: phy: Create SFP phy_port before registering upstream Maxime Chevallier
@ 2026-09-09 9:39 ` Maxime Chevallier
2026-09-09 9:39 ` [PATCH net-next v17 08/10] netlink: specs: Add ethernet port listing with ethtool Maxime Chevallier
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Maxime Chevallier @ 2026-09-09 9:39 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, Frank Wunderlich,
Pietro Ameruoso
MII phy_ports are not meant to be connected directly to a link partner.
They are meant to feed into some media converter devices that will
expose an MDI phy_port, so far we only support SFP modules for that.
In the case an MDI phy_port is backed by an MII port (e.g. a SFP
module's port, backed by the SFP cage port), let's keep track of the
port id of the MII port backing it.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/phy_device.c | 29 +++++++++++++++++++++++++++--
drivers/net/phy/phylink.c | 5 +++++
include/linux/phy.h | 4 ++++
include/linux/phy_port.h | 3 +++
4 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 26634ef274f3..561d19edf331 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1493,6 +1493,7 @@ static int phy_sfp_connect_phy(void *upstream, struct phy_device *phy)
int ret;
phydev->has_sfp_mod_phy = true;
+ phy_set_upstream_port(phy, phydev->sfp_cage_port);
/* If we aren't attached to a netdev, we can't add the SFP PHY to its
* topology.
@@ -1526,6 +1527,8 @@ static void phy_sfp_disconnect_phy(void *upstream, struct phy_device *phy)
if (dev)
phy_link_topo_del_phy(dev, phy);
+
+ phy_set_upstream_port(phy, NULL);
}
/**
@@ -1661,6 +1664,8 @@ static int phy_add_sfp_mod_port(struct phy_device *phydev)
*/
phydev->mod_port = port;
+ port->upstream_port = phydev->sfp_cage_port;
+
return 0;
}
@@ -1816,6 +1821,8 @@ static int phy_sfp_probe(struct phy_device *phydev)
}
}
+ phydev->sfp_cage_port = port;
+
ret = sfp_bus_add_upstream(bus, phydev, &sfp_phydev_ops);
if (ret)
goto out_port;
@@ -1825,14 +1832,13 @@ static int phy_sfp_probe(struct phy_device *phydev)
*/
sfp_bus_put(bus);
- phydev->sfp_cage_port = port;
-
return ret;
out_port:
if (port) {
phy_del_port(phydev, port);
phy_port_destroy(port);
+ phydev->sfp_cage_port = NULL;
}
out_sfp:
sfp_bus_put(bus);
@@ -3777,6 +3783,25 @@ struct phy_port *phy_get_sfp_port(struct phy_device *phydev)
}
EXPORT_SYMBOL_GPL(phy_get_sfp_port);
+/**
+ * phy_set_upstream_port() - Sets the phy_port controlling the MII this PHY is
+ * attached to.
+ * @phydev: pointer to the PHY device we set the upstream of.
+ * @port: The phy_port upstream of this PHY, can be NULL.
+ */
+void phy_set_upstream_port(struct phy_device *phydev, struct phy_port *port)
+{
+ struct phy_port *local_port;
+
+ ASSERT_RTNL();
+
+ phydev->upstream_port = port;
+
+ phy_for_each_port(phydev, local_port)
+ local_port->upstream_port = port;
+}
+EXPORT_SYMBOL_GPL(phy_set_upstream_port);
+
/**
* fwnode_mdio_find_device - Given a fwnode, find the mdio_device
* @fwnode: pointer to the mdio_device's fwnode
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 5a8c66866d17..d05cde44f401 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -4027,6 +4027,8 @@ static int phylink_add_sfp_mod_port(struct phylink *pl)
}
}
+ port->upstream_port = pl->sfp_cage_port;
+
pl->mod_port = port;
return 0;
@@ -4130,6 +4132,8 @@ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces,
pl->config->supported_interfaces);
+ phy_set_upstream_port(phy, pl->sfp_cage_port);
+
/* Do the initial configuration */
return phylink_sfp_config_phy(pl, phy);
}
@@ -4138,6 +4142,7 @@ static void phylink_sfp_disconnect_phy(void *upstream,
struct phy_device *phydev)
{
phylink_disconnect_phy(upstream);
+ phy_set_upstream_port(phydev, NULL);
}
static const struct sfp_upstream_ops sfp_phylink_ops = {
diff --git a/include/linux/phy.h b/include/linux/phy.h
index cb579b8a5b5f..335821eb2217 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -615,6 +615,7 @@ struct phy_oatc14_sqi_capability {
* @sfp_bus: SFP bus attached to this PHY's fiber port
* @sfp_cage_port: The phy_port connected to the downstream SFP cage
* @mod_port: phy_port representing the SFP module, if it is phy-less
+ * @upstream_port: phy_port this PHY's MII attaches to, if any
* @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.
@@ -809,6 +810,7 @@ struct phy_device {
struct sfp_bus *sfp_bus;
struct phy_port *sfp_cage_port;
struct phy_port *mod_port;
+ struct phy_port *upstream_port;
struct phylink *phylink;
struct net_device *attached_dev;
struct mii_timestamper *mii_ts;
@@ -2493,6 +2495,8 @@ int __phy_hwtstamp_set(struct phy_device *phydev,
struct phy_port *phy_get_sfp_port(struct phy_device *phydev);
+void phy_set_upstream_port(struct phy_device *phydev, struct phy_port *port);
+
/**
* phy_module_driver() - Helper macro for registering PHY drivers
* @__phy_drivers: array of PHY drivers to register
diff --git a/include/linux/phy_port.h b/include/linux/phy_port.h
index 4e2a3fdd2f2e..8f45c031cbc1 100644
--- a/include/linux/phy_port.h
+++ b/include/linux/phy_port.h
@@ -40,6 +40,8 @@ struct phy_port_ops {
* @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
+ * @upstream_port: Indicates the MII port that feeds this port, if any,
+ * e.g. the SFP cage port for a SFP module port.
* @ops: Callback ops implemented by the port controller
* @pairs: The number of pairs this port has, 0 if not applicable
* @mediums: Bitmask of the physical mediums this port provides access to
@@ -59,6 +61,7 @@ struct phy_port {
union {
struct phy_device *phy;
};
+ struct phy_port *upstream_port;
const struct phy_port_ops *ops;
--
2.55.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH net-next v17 08/10] netlink: specs: Add ethernet port listing with ethtool
2026-09-09 9:39 [PATCH net-next v17 00/10] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
` (4 preceding siblings ...)
2026-09-09 9:39 ` [PATCH net-next v17 06/10] net: phy: phy_port: Store information about a port's upstream Maxime Chevallier
@ 2026-09-09 9:39 ` Maxime Chevallier
2026-09-09 9:39 ` [PATCH net-next v17 10/10] Documentation: networking: Update the phy_port infrastructure description Maxime Chevallier
2026-09-09 13:34 ` [PATCH net-next v17 00/10] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
7 siblings, 0 replies; 9+ messages in thread
From: Maxime Chevallier @ 2026-09-09 9:39 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, Frank Wunderlich,
Pietro Ameruoso
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 | 55 +++++++++++++++++++
Documentation/networking/ethtool-netlink.rst | 34 ++++++++++++
.../uapi/linux/ethtool_netlink_generated.h | 22 ++++++++
3 files changed, 111 insertions(+)
diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml
index 5dd4d1b5d94b..35e028c0be29 100644
--- a/Documentation/netlink/specs/ethtool.yaml
+++ b/Documentation/netlink/specs/ethtool.yaml
@@ -210,6 +210,11 @@ definitions:
-
name: discard
value: 31
+ -
+ name: port-type
+ doc: type of physical connector
+ type: enum
+ entries: [mdi, sfp]
attribute-sets:
-
@@ -1905,6 +1910,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: u32
+ enum: port-type
+ -
+ name: upstream-port
+ type: u32
operations:
enum-model: directional
@@ -2859,6 +2890,30 @@ operations:
- worst-channel
- link
dump: *mse-get-op
+ -
+ name: port-get
+ doc: Get ports attached to an interface
+
+ attribute-set: port
+
+ do:
+ request:
+ attributes:
+ - header
+ - id
+ reply: &port-get-op-reply
+ attributes:
+ - header
+ - id
+ - supported-modes
+ - supported-interfaces
+ - type
+ - upstream-port
+ dump:
+ request:
+ attributes:
+ - header
+ reply: *port-get-op-reply
mcast-groups:
list:
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index e92abf45faf5..b4326c89b075 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -2537,6 +2537,39 @@ 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_UPSTREAM_PORT`` u32 If any, the index of the MII
+ port that feeds into this
+ port.
+ ======================================= ====== =============================
+
Request translation
===================
@@ -2647,4 +2680,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 8134baf7860f..660e0c08a766 100644
--- a/include/uapi/linux/ethtool_netlink_generated.h
+++ b/include/uapi/linux/ethtool_netlink_generated.h
@@ -78,6 +78,14 @@ enum ethtool_pse_event {
ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR = 64,
};
+/*
+ * type of physical connector
+ */
+enum ethtool_port_type {
+ ETHTOOL_PORT_TYPE_MDI,
+ ETHTOOL_PORT_TYPE_SFP,
+};
+
enum {
ETHTOOL_A_HEADER_UNSPEC,
ETHTOOL_A_HEADER_DEV_INDEX,
@@ -840,6 +848,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_UPSTREAM_PORT,
+
+ __ETHTOOL_A_PORT_CNT,
+ ETHTOOL_A_PORT_MAX = (__ETHTOOL_A_PORT_CNT - 1)
+};
+
enum {
ETHTOOL_MSG_USER_NONE = 0,
ETHTOOL_MSG_STRSET_GET = 1,
@@ -893,6 +913,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)
@@ -954,6 +975,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.55.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH net-next v17 10/10] Documentation: networking: Update the phy_port infrastructure description
2026-09-09 9:39 [PATCH net-next v17 00/10] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
` (5 preceding siblings ...)
2026-09-09 9:39 ` [PATCH net-next v17 08/10] netlink: specs: Add ethernet port listing with ethtool Maxime Chevallier
@ 2026-09-09 9:39 ` Maxime Chevallier
2026-09-09 13:34 ` [PATCH net-next v17 00/10] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
7 siblings, 0 replies; 9+ messages in thread
From: Maxime Chevallier @ 2026-09-09 9:39 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, Frank Wunderlich,
Pietro Ameruoso
With SFP now properly supported with phy_port, add some details in the
documentation. Fix a typo along the way (driver -> driven).
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
Documentation/networking/phy-port.rst | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/Documentation/networking/phy-port.rst b/Documentation/networking/phy-port.rst
index 6e28d9094bce..2a9b1ec93b70 100644
--- a/Documentation/networking/phy-port.rst
+++ b/Documentation/networking/phy-port.rst
@@ -99,13 +99,29 @@ will eventually be able to report its own ksettings::
(_____)-----| Port |
+------+
+SFP ports
+=========
+
+SFP interfaces involve 2 distinct components, each represented by
+a :c:type:`struct phy_port <phy_port>` instance :
+
+ - The SFP cage itself is a :c:type:`struct phy_port <phy_port>`. It's special
+ in that it's not an MDI interface, but rather a hot-pluggable MII.
+ The :c:type:`struct phy_port <phy_port>` associated to it lists the different
+ MII interfaces we can use on the cage.
+
+ - The SFP module, when inserted, will also be associated to a
+ :c:type:`struct phy_port <phy_port>`, that represents the various linkmodes
+ that it gives access to. The module's :c:type:`struct phy_port <phy_port>`
+ doesn't supersede the cage's port, it references it through
+ the :c:type:`struct phy_port <phy_port>` :c:member:`upstream_port` field.
+
Next steps
==========
-As of writing this documentation, only ports controlled by PHY devices are
-supported. The next steps will be to add the Netlink API to expose these
-to userspace and add support for raw ports (controlled by some firmware, and directly
-managed by the NIC driver).
+As of writing this documentation, the port's presence and information can only
+be queried, and it's not possible to change any of the port's settings or select
+which one should be used.
Another parallel task is the introduction of a MII muxing framework to allow the
-control of non-PHY driver multi-port setups.
+control of non-PHY driven multi-port setups.
--
2.55.0
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH net-next v17 00/10] net: phy_port: SFP modules representation and phy_port listing
2026-09-09 9:39 [PATCH net-next v17 00/10] net: phy_port: SFP modules representation and phy_port listing Maxime Chevallier
` (6 preceding siblings ...)
2026-09-09 9:39 ` [PATCH net-next v17 10/10] Documentation: networking: Update the phy_port infrastructure description Maxime Chevallier
@ 2026-09-09 13:34 ` Maxime Chevallier
7 siblings, 0 replies; 9+ messages in thread
From: Maxime Chevallier @ 2026-09-09 13:34 UTC (permalink / raw)
To: 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, Romain Gantois,
Daniel Golle, Dimitri Fedrau, Frank Wunderlich, Pietro Ameruoso
Hi,
On 9/9/26 11:39, Maxime Chevallier wrote:
> Hello everyone,
>
> Here's V17 for the phy_port improved SFP support and netlink interface.
Looks like I got ratelimited by my mail provider, it's the second series
today that partially makes it to the ML :(
I'll resend after 24h cooldown,
Maxime
>
> V17 addresses the port_id wrapparound with the xarray insertion, and the
> missing comment during the ethtool header regen from the YNL specs.
>
> This work extends 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
> Supported MII interfaces : sgmii, 1000base-x, 2500base-x
> Port type: sfp
>
> - Get Combo-ports supported modes, on each port :
>
> # ethtool --show-ports eth1
>
> Port for eth1:
> Port id: 1
> Supported link modes: 10baseT/Half 10baseT/Full
> 100baseT/Half 100baseT/Full
> 1000baseT/Full
> 10000baseT/Full
> 2500baseT/Full
> 5000baseT/Full
>
> Port type: mdi
>
> Port for eth1:
> Port id: 2
> 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
> Supported link modes: 10baseT/Half 10baseT/Full
> 100baseT/Half 100baseT/Full
> 1000baseT/Full
> 10000baseT/Full
> 2500baseT/Full
> 5000baseT/Full
> Port type: mdi
>
> Port for eth1:
> Port id: 2
> Supported MII interfaces : 10gbase-r
> Port type: sfp
>
> Port for eth1:
> Port id: 3
> Upstream id: 2
> 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
>
> Changelog :
>
> Changes in v17:
> - Handle port index wraparound
> - Regen the ethtool headers, now with the comment :)
>
> Changes in v16:
> https://lore.kernel.org/r/20260902212135.1805948-1-maxime.chevallier@bootlin.com
> - unregister phy_ports at phy_detach
> - typos in patch 1 (of -> or)
> - Fix the netlink specs
>
> Changes in v15:
> https://lore.kernel.org/netdev/20260801074332.98755-1-maxime.chevallier@bootlin.com/
> - Fail on port access for ops-locked devices
> - Use a direct phy_port pointer for upstream tracking
> - Addressed the kdoc issues
>
> Changes in v14:
> https://lore.kernel.org/netdev/20260720174808.139573-1-maxime.chevallier@bootlin.com/
> - Added a big comment on the first patch for the topo alloc potential
> races
> - Fixed the multi-buff DUMP on last patch with a separate iterator for
> dumps
> - Fixed some typos in the documentation
>
> Changes in V13:
> V13: https://lore.kernel.org/r/20260701110427.143945-1-maxime.chevallier@bootlin.com
> - Rebase on net-next
> - Fix the SFP bus cleanup path in patch 5
>
> Changes in V12:
> V12: https://lore.kernel.org/r/20260615153907.862987-1-maxime.chevallier@bootlin.com
> - Rebased on net-next, including fixes on the phy probing and cleanup
> paths
> - Rebased on Jakub's netdev_ops_locked changes in phy_link_topology
> - Fixed some typos reported by Andrew and sashiko in the documentation
>
> Changes in v11:
> V11:https://lore.kernel.org/r/20260521121040.1199622-1-maxime.chevallier@bootlin.com
> - Aggregated Andrew's reviews :)
> - Removed the "vacant" field, replaced it with "upstream_port"
>
> Changes in V10:
> V10: https://lore.kernel.org/r/20260513130521.1064094-1-maxime.chevallier@bootlin.com
> - Rebase on net-next
> - Rename phylink/phy_device sfp_bus_port to sfp_cage_port
> - Sashiko's reviews were mostly unrealistic or wrong :(
>
> Changes in V9:
> V9: https://lore.kernel.org/r/20260403123755.175742-1-maxime.chevallier@bootlin.com
> - Added missing netlink doc updates for u8->u32 conversion
> - Removed dead code with a condition that can never be true in
> phylink's mod_port code
> - Fixed the error path in phy_sfp_connect_phy
>
> Changes in v8:
> V8: https://lore.kernel.org/r/20260325081937.571115-1-maxime.chevallier@bootlin.com
> - Set the new phydev.has_sfp_mod_phy field when we're sure that no
> errors occured
> - Fix formatting of the copyright info in ethnl port
> - Use a policy to validate the range of port_id
> - Use GENL_REQ_ATTR_CHECK
> - alpha-sort headers
> - use u32 in netlink messages
> - return better error codes
> - don't check the skb len, the core does that
>
> Changes in V7:
> V7: https://lore.kernel.org/all/20260309152747.702373-1-maxime.chevallier@bootlin.com/
> - Changed the port cleanup path to use list_for_each_entry_continue_reverse
> - Adjusted the cleanup path in phylink for the port vacant state
> - Pass the right cmd for the netlink dump message
>
> Changes in V6:
> V6: https://lore.kernel.org/r/20260304145444.442334-1-maxime.chevallier@bootlin.com
> - Added some comments in th mod_port cleanup
> - changed some kmalloc to kmalloc_obj
> - Removed some phy_link_topo_del_port that wasn't needed
>
> Changes in V5:
> V5: https://lore.kernel.org/r/20260205092317.755906-1-maxime.chevallier@bootlin.com
> - Fixed a check on a potentially un-initialized pointer, reported by
> Simon
> - Fixed a documentation formatting issue
> - Remove a stray pr_info
> - Rebased on net-next
>
> Changes in V4:
> V4 : https://lore.kernel.org/netdev/20260203172839.548524-1-maxime.chevallier@bootlin.com/
> - Add a cleanup patch for the of port parsing
> - Added a match to sync the port's linkmodes with the PHY's for OF
> ports
> - Added RTNL assert in the port_get topo helper
> - nullify the bus port for phylink support
> - Fix some typos
>
> Changes in V3:
> V3: https://lore.kernel.org/netdev/20260201151249.642015-1-maxime.chevallier@bootlin.com/
> - Remove the sfp bus ops for nophy, and use .module_start() as
> suggested by Russell
> - Added missing cleanup for the topology, as per AI review
> - Fixed a few typos as per Romain's review
> - Changed "occupied" to "vacant" as per Romain's review
> - Added missing checks for null ports, per AI review
>
> Changes in V2:
> V2: https://lore.kernel.org/netdev/20260128204526.170927-1-maxime.chevallier@bootlin.com/
> - Fix the cleanup path of phy_link_topo_add_phy, as per AI review
> - Fix the cleanup path of phy_sfp_probe, as per AI review
> - Fix the call-site of the disconnect_nophy sfp bus ops, per AI review
> - Fix the netdev-less case uin phylink, per AI review
> - Fix the prototype of phy_link_topo_get_port for the stubs
> - Dropped patch 11. It ended-up breaking 'allnoconfig', so instead we
> built a phy_interface_names array in net/ethtool/netlink.c
> - Fix an ethool-netlink spec discrepancy with the type of an attribute
> - Fix the size computation in the netlink port API
> - Fix the cleanup path in the netlink port API
>
> V1: https://lore.kernel.org/netdev/20260127134202.8208-1-maxime.chevallier@bootlin.com/
>
> Maxime Chevallier (10):
> 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 cages
> net: phy: Create SFP phy_port before registering upstream
> net: phy: Represent PHY-less SFP modules with phy_port
> net: phy: phy_port: Store information about a port's upstream
> net: phy: phy_link_topology: Add a helper to retrieve ports
> netlink: specs: Add ethernet port listing with ethtool
> net: ethtool: Introduce ethtool command to list ports
> Documentation: networking: Update the phy_port infrastructure
> description
>
> Documentation/netlink/specs/ethtool.yaml | 55 +++
> Documentation/networking/ethtool-netlink.rst | 34 ++
> Documentation/networking/phy-port.rst | 26 +-
> MAINTAINERS | 1 +
> drivers/net/phy/phy-caps.h | 2 +
> drivers/net/phy/phy_caps.c | 26 ++
> drivers/net/phy/phy_device.c | 186 +++++++--
> drivers/net/phy/phy_link_topology.c | 101 ++++-
> drivers/net/phy/phylink.c | 128 +++++-
> include/linux/phy.h | 10 +
> include/linux/phy_link_topology.h | 44 ++
> include/linux/phy_port.h | 5 +
> .../uapi/linux/ethtool_netlink_generated.h | 22 +
> net/core/dev.c | 1 +
> net/ethtool/Makefile | 2 +-
> net/ethtool/netlink.c | 25 ++
> net/ethtool/netlink.h | 8 +
> net/ethtool/port.c | 382 ++++++++++++++++++
> 18 files changed, 1020 insertions(+), 38 deletions(-)
> create mode 100644 net/ethtool/port.c
>
^ permalink raw reply [flat|nested] 9+ messages in thread