Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net: phy: marvell10g: Support SFP through phy_port

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.

Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Tested-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Link: https://patch.msgid.link/20260108080041.553250-11-maxime.chevallier@bootlin.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Maxime Chevallier and committed by
Jakub Kicinski
35d1a546 1384e138

+75 -21
+30 -21
drivers/net/phy/marvell10g.c
··· 28 28 #include <linux/hwmon.h> 29 29 #include <linux/marvell_phy.h> 30 30 #include <linux/phy.h> 31 - #include <linux/sfp.h> 31 + #include <linux/phy_port.h> 32 32 #include <linux/netdevice.h> 33 33 34 34 #define MV_PHY_ALASKA_NBT_QUIRK_MASK 0xfffffffe ··· 463 463 return err; 464 464 } 465 465 466 - static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) 466 + static int mv3310_attach_mii_port(struct phy_device *phydev, 467 + struct phy_port *port) 467 468 { 468 - struct phy_device *phydev = upstream; 469 - const struct sfp_module_caps *caps; 470 - phy_interface_t iface; 471 - 472 - caps = sfp_get_module_caps(phydev->sfp_bus); 473 - iface = sfp_select_interface(phydev->sfp_bus, caps->link_modes); 474 - 475 - if (iface != PHY_INTERFACE_MODE_10GBASER) { 476 - dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); 477 - return -EINVAL; 478 - } 469 + __set_bit(PHY_INTERFACE_MODE_10GBASER, port->interfaces); 479 470 return 0; 480 471 } 481 472 482 - static const struct sfp_upstream_ops mv3310_sfp_ops = { 483 - .attach = phy_sfp_attach, 484 - .detach = phy_sfp_detach, 485 - .connect_phy = phy_sfp_connect_phy, 486 - .disconnect_phy = phy_sfp_disconnect_phy, 487 - .module_insert = mv3310_sfp_insert, 488 - }; 473 + static int mv3310_attach_mdi_port(struct phy_device *phydev, 474 + struct phy_port *port) 475 + { 476 + /* This PHY can do combo-ports, i.e. 2 MDI outputs, usually one 477 + * of them going to an SFP and the other one to a RJ45 478 + * connector. If we don't have any representation for the port 479 + * in DT, and we are dealing with a non-SFP port, then we 480 + * mask the port's capabilities to report BaseT-only modes 481 + */ 482 + if (port->not_described) 483 + return phy_port_restrict_mediums(port, 484 + BIT(ETHTOOL_LINK_MEDIUM_BASET)); 485 + 486 + return 0; 487 + } 489 488 490 489 static int mv3310_probe(struct phy_device *phydev) 491 490 { ··· 543 544 544 545 chip->init_supported_interfaces(priv->supported_interfaces); 545 546 546 - return phy_sfp_probe(phydev, &mv3310_sfp_ops); 547 + phydev->max_n_ports = 2; 548 + 549 + return 0; 547 550 } 548 551 549 552 static void mv3310_remove(struct phy_device *phydev) ··· 1406 1405 .set_loopback = genphy_c45_loopback, 1407 1406 .get_wol = mv3110_get_wol, 1408 1407 .set_wol = mv3110_set_wol, 1408 + .attach_mii_port = mv3310_attach_mii_port, 1409 + .attach_mdi_port = mv3310_attach_mdi_port, 1409 1410 }, 1410 1411 { 1411 1412 .phy_id = MARVELL_PHY_ID_88X3310, ··· 1427 1424 .set_tunable = mv3310_set_tunable, 1428 1425 .remove = mv3310_remove, 1429 1426 .set_loopback = genphy_c45_loopback, 1427 + .attach_mii_port = mv3310_attach_mii_port, 1428 + .attach_mdi_port = mv3310_attach_mdi_port, 1430 1429 }, 1431 1430 { 1432 1431 .phy_id = MARVELL_PHY_ID_88E2110, ··· 1449 1444 .set_loopback = genphy_c45_loopback, 1450 1445 .get_wol = mv3110_get_wol, 1451 1446 .set_wol = mv3110_set_wol, 1447 + .attach_mii_port = mv3310_attach_mii_port, 1448 + .attach_mdi_port = mv3310_attach_mdi_port, 1452 1449 }, 1453 1450 { 1454 1451 .phy_id = MARVELL_PHY_ID_88E2110, ··· 1469 1462 .set_tunable = mv3310_set_tunable, 1470 1463 .remove = mv3310_remove, 1471 1464 .set_loopback = genphy_c45_loopback, 1465 + .attach_mii_port = mv3310_attach_mii_port, 1466 + .attach_mdi_port = mv3310_attach_mdi_port, 1472 1467 }, 1473 1468 }; 1474 1469
+44
drivers/net/phy/phy_port.c
··· 150 150 EXPORT_SYMBOL_GPL(phy_port_update_supported); 151 151 152 152 /** 153 + * phy_port_filter_supported() - Make sure that port->supported match port->mediums 154 + * @port: The port to filter 155 + * 156 + * After updating a port's mediums to a more restricted subset, this helper will 157 + * make sure that port->supported only contains linkmodes that are compatible 158 + * with port->mediums. 159 + */ 160 + static void phy_port_filter_supported(struct phy_port *port) 161 + { 162 + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0 }; 163 + int i; 164 + 165 + for_each_set_bit(i, &port->mediums, __ETHTOOL_LINK_MEDIUM_LAST) 166 + phy_caps_medium_get_supported(supported, i, port->pairs); 167 + 168 + linkmode_and(port->supported, port->supported, supported); 169 + } 170 + 171 + /** 172 + * phy_port_restrict_mediums - Mask away some of the port's supported mediums 173 + * @port: The port to act upon 174 + * @mediums: A mask of mediums to support on the port 175 + * 176 + * This helper allows removing some mediums from a port's list of supported 177 + * mediums, which occurs once we have enough information about the port to 178 + * know its nature. 179 + * 180 + * Returns: 0 if the change was donne correctly, a negative value otherwise. 181 + */ 182 + int phy_port_restrict_mediums(struct phy_port *port, unsigned long mediums) 183 + { 184 + /* We forbid ending-up with a port with empty mediums */ 185 + if (!(port->mediums & mediums)) 186 + return -EINVAL; 187 + 188 + port->mediums &= mediums; 189 + 190 + phy_port_filter_supported(port); 191 + 192 + return 0; 193 + } 194 + EXPORT_SYMBOL_GPL(phy_port_restrict_mediums); 195 + 196 + /** 153 197 * phy_port_get_type() - get the PORT_* attribute for that port. 154 198 * @port: The port we want the information from 155 199 *
+1
include/linux/phy_port.h
··· 92 92 } 93 93 94 94 void phy_port_update_supported(struct phy_port *port); 95 + int phy_port_restrict_mediums(struct phy_port *port, unsigned long mediums); 95 96 96 97 int phy_port_get_type(struct phy_port *port); 97 98