[PATCH net-next v8 10/15] net: phy: marvell10g: Support SFP through phy_port
From: Maxime Chevallier <maxime.chevallier@bootlin.com>
Date: 2025-07-10 13:45:56
Also in:
linux-arm-kernel, linux-arm-msm, linux-devicetree, lkml
Subsystem:
ethernet phy library, marvell mv88x3310 phy driver, networking drivers, networking [ethtool phy port], the rest · Maintainers:
Andrew Lunn, Heiner Kallweit, Russell King, Marek Behún, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Maxime Chevallier, Linus Torvalds
Convert the Marvell10G driver to use the generic SFP handling, through a dedicated .attach_port() handler to populate the port's supported interfaces. As the 88x3310 supports multiple MDI, the .attach_port() logic handles both SFP attach with 10GBaseR support, and support for the "regular" port that usually is a BaseT port. Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com> --- drivers/net/phy/marvell10g.c | 47 +++++++++++++++++++----------------- drivers/net/phy/phy_port.c | 20 +++++++++++++++ include/linux/phy_port.h | 1 + 3 files changed, 46 insertions(+), 22 deletions(-)
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 13e81dff42c1..7cb638804a3f 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c@@ -28,7 +28,7 @@ #include <linux/hwmon.h> #include <linux/marvell_phy.h> #include <linux/phy.h> -#include <linux/sfp.h> +#include <linux/phy_port.h> #include <linux/netdevice.h> #define MV_PHY_ALASKA_NBT_QUIRK_MASK 0xfffffffe
@@ -463,36 +463,31 @@ static int mv3310_set_edpd(struct phy_device *phydev, u16 edpd) return err; } -static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) +static int mv3310_attach_port(struct phy_device *phydev, struct phy_port *port) { - struct phy_device *phydev = upstream; - __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; - DECLARE_PHY_INTERFACE_MASK(interfaces); - phy_interface_t iface; - - sfp_parse_support(phydev->sfp_bus, id, support, interfaces); - iface = sfp_select_interface(phydev->sfp_bus, support); - - if (iface != PHY_INTERFACE_MODE_10GBASER) { - dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); - return -EINVAL; + if (port->is_mii) { + __set_bit(PHY_INTERFACE_MODE_10GBASER, port->interfaces); + } else if (port->not_described) { + /* This PHY can do combo-ports, i.e. 2 MDI outputs, usually one + * of them going to an SFP and the other one to a RJ45 + * connector. If we don't have any representation for the port + * in DT, and we are dealing with a non-SFP port, then we + * mask the port's capabilities to report BaseT-only modes + */ + port->mediums = BIT(ETHTOOL_LINK_MEDIUM_BASET); + + phy_port_filter_supported(port); } + return 0; } -static const struct sfp_upstream_ops mv3310_sfp_ops = { - .attach = phy_sfp_attach, - .detach = phy_sfp_detach, - .connect_phy = phy_sfp_connect_phy, - .disconnect_phy = phy_sfp_disconnect_phy, - .module_insert = mv3310_sfp_insert, -}; - static int mv3310_probe(struct phy_device *phydev) { const struct mv3310_chip *chip = to_mv3310_chip(phydev); struct mv3310_priv *priv; u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN; + DECLARE_PHY_INTERFACE_MASK(interfaces); int ret; if (!phydev->is_c45 ||
@@ -543,9 +538,13 @@ static int mv3310_probe(struct phy_device *phydev) if (ret) return ret; + __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); + chip->init_supported_interfaces(priv->supported_interfaces); - return phy_sfp_probe(phydev, &mv3310_sfp_ops); + phydev->max_n_ports = 2; + + return 0; } static void mv3310_remove(struct phy_device *phydev)
@@ -1406,6 +1405,7 @@ static struct phy_driver mv3310_drivers[] = { .set_loopback = genphy_c45_loopback, .get_wol = mv3110_get_wol, .set_wol = mv3110_set_wol, + .attach_port = mv3310_attach_port, }, { .phy_id = MARVELL_PHY_ID_88X3310,
@@ -1425,6 +1425,7 @@ static struct phy_driver mv3310_drivers[] = { .set_tunable = mv3310_set_tunable, .remove = mv3310_remove, .set_loopback = genphy_c45_loopback, + .attach_port = mv3310_attach_port, }, { .phy_id = MARVELL_PHY_ID_88E2110,
@@ -1445,6 +1446,7 @@ static struct phy_driver mv3310_drivers[] = { .set_loopback = genphy_c45_loopback, .get_wol = mv3110_get_wol, .set_wol = mv3110_set_wol, + .attach_port = mv3310_attach_port, }, { .phy_id = MARVELL_PHY_ID_88E2110,
@@ -1463,6 +1465,7 @@ static struct phy_driver mv3310_drivers[] = { .set_tunable = mv3310_set_tunable, .remove = mv3310_remove, .set_loopback = genphy_c45_loopback, + .attach_port = mv3310_attach_port, }, };
diff --git a/drivers/net/phy/phy_port.c b/drivers/net/phy/phy_port.c
index 36de8c5c9ad5..cd7ace64ed4b 100644
--- a/drivers/net/phy/phy_port.c
+++ b/drivers/net/phy/phy_port.c@@ -131,6 +131,26 @@ void phy_port_update_supported(struct phy_port *port) } EXPORT_SYMBOL_GPL(phy_port_update_supported); +/** + * phy_port_filter_supported() - Make sure that port->supported match port->mediums + * @port: The port to filter + * + * After updating a port's mediums to a more restricted subset, this helper will + * make sure that port->supported only contains linkmodes that are compatible + * with port->mediums. + */ +void phy_port_filter_supported(struct phy_port *port) +{ + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0 }; + int i; + + for_each_set_bit(i, &port->mediums, __ETHTOOL_LINK_MEDIUM_LAST) + phy_caps_medium_get_supported(supported, i, port->lanes); + + linkmode_and(port->supported, port->supported, supported); +} +EXPORT_SYMBOL_GPL(phy_port_filter_supported); + /** * phy_port_get_type() - get the PORT_* attribut for that port. * @port: The port we want the information from
diff --git a/include/linux/phy_port.h b/include/linux/phy_port.h
index f47ac5f5ef9e..ce735d81bcd0 100644
--- a/include/linux/phy_port.h
+++ b/include/linux/phy_port.h@@ -90,6 +90,7 @@ static inline bool phy_port_is_fiber(struct phy_port *port) } void phy_port_update_supported(struct phy_port *port); +void phy_port_filter_supported(struct phy_port *port); int phy_port_get_type(struct phy_port *port);
--
2.49.0