]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
net: phy: add helpers to handle sfp phy connect/disconnect
authorMaxime Chevallier <maxime.chevallier@bootlin.com>
Thu, 4 Apr 2024 09:29:53 +0000 (11:29 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sat, 6 Apr 2024 17:25:14 +0000 (18:25 +0100)
There are a few PHY drivers that can handle SFP modules through their
sfp_upstream_ops. Introduce Phylib helpers to keep track of connected
SFP PHYs in a netdevice's namespace, by adding the SFP PHY to the
upstream PHY's netdev's namespace.

By doing so, these SFP PHYs can be enumerated and exposed to users,
which will be able to use their capabilities.

Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/marvell-88x2222.c
drivers/net/phy/marvell.c
drivers/net/phy/marvell10g.c
drivers/net/phy/phy_device.c
drivers/net/phy/qcom/at803x.c
drivers/net/phy/qcom/qca807x.c
include/linux/phy.h

index b88398e6872bcf4055200ede6bc928a9825abbb5..0b777cdd7078b14f3e12731f3956f1f1492d3dc7 100644 (file)
@@ -553,6 +553,8 @@ static const struct sfp_upstream_ops sfp_phy_ops = {
        .link_down = mv2222_sfp_link_down,
        .attach = phy_sfp_attach,
        .detach = phy_sfp_detach,
+       .connect_phy = phy_sfp_connect_phy,
+       .disconnect_phy = phy_sfp_disconnect_phy,
 };
 
 static int mv2222_probe(struct phy_device *phydev)
index 0003276452f6ab3197cbf8959c88ee3d5b026726..860dc4001d415b2a00b2d646ebf8e352f9061c57 100644 (file)
@@ -3550,6 +3550,8 @@ static const struct sfp_upstream_ops m88e1510_sfp_ops = {
        .module_remove = m88e1510_sfp_remove,
        .attach = phy_sfp_attach,
        .detach = phy_sfp_detach,
+       .connect_phy = phy_sfp_connect_phy,
+       .disconnect_phy = phy_sfp_disconnect_phy,
 };
 
 static int m88e1510_probe(struct phy_device *phydev)
index ad43e280930c35eaef7454813143c1a2eb8a0fae..6642eb642d4bdd3880ddd7fdbc3471bc2c78e5ea 100644 (file)
@@ -503,6 +503,8 @@ static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
 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,
 };
 
index 452fc8b3406deb5020e809347abac68711bdc06e..616bd7ba46cbf18eee3c4297208804d67cd38ef9 100644 (file)
@@ -277,6 +277,14 @@ static void phy_mdio_device_remove(struct mdio_device *mdiodev)
 
 static struct phy_driver genphy_driver;
 
+static struct phy_link_topology *phy_get_link_topology(struct phy_device *phydev)
+{
+       if (phydev->attached_dev)
+               return phydev->attached_dev->link_topo;
+
+       return NULL;
+}
+
 static LIST_HEAD(phy_fixup_list);
 static DEFINE_MUTEX(phy_fixup_lock);
 
@@ -1370,6 +1378,46 @@ phy_standalone_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(phy_standalone);
 
+/**
+ * phy_sfp_connect_phy - Connect the SFP module's PHY to the upstream PHY
+ * @upstream: pointer to the upstream phy device
+ * @phy: pointer to the SFP module's phy device
+ *
+ * This helper allows keeping track of PHY devices on the link. It adds the
+ * SFP module's phy to the phy namespace of the upstream phy
+ */
+int phy_sfp_connect_phy(void *upstream, struct phy_device *phy)
+{
+       struct phy_device *phydev = upstream;
+       struct phy_link_topology *topo = phy_get_link_topology(phydev);
+
+       if (topo)
+               return phy_link_topo_add_phy(topo, phy, PHY_UPSTREAM_PHY, phydev);
+
+       return 0;
+}
+EXPORT_SYMBOL(phy_sfp_connect_phy);
+
+/**
+ * phy_sfp_disconnect_phy - Disconnect the SFP module's PHY from the upstream PHY
+ * @upstream: pointer to the upstream phy device
+ * @phy: pointer to the SFP module's phy device
+ *
+ * This helper allows keeping track of PHY devices on the link. It removes the
+ * SFP module's phy to the phy namespace of the upstream phy. As the module phy
+ * will be destroyed, re-inserting the same module will add a new phy with a
+ * new index.
+ */
+void phy_sfp_disconnect_phy(void *upstream, struct phy_device *phy)
+{
+       struct phy_device *phydev = upstream;
+       struct phy_link_topology *topo = phy_get_link_topology(phydev);
+
+       if (topo)
+               phy_link_topo_del_phy(topo, phy);
+}
+EXPORT_SYMBOL(phy_sfp_disconnect_phy);
+
 /**
  * phy_sfp_attach - attach the SFP bus to the PHY upstream network device
  * @upstream: pointer to the phy device
index c8f83e5f78ab9c74d69aa4030185653d04bba430..105602581a03368416789bcd07dee38baae05d58 100644 (file)
@@ -770,6 +770,8 @@ static const struct sfp_upstream_ops at8031_sfp_ops = {
        .attach = phy_sfp_attach,
        .detach = phy_sfp_detach,
        .module_insert = at8031_sfp_insert,
+       .connect_phy = phy_sfp_connect_phy,
+       .disconnect_phy = phy_sfp_disconnect_phy,
 };
 
 static int at8031_parse_dt(struct phy_device *phydev)
index 672c6929119a62ae00f0075223b854d7a9d9652b..5eb0ab1cb70e96d6589a880c2d90bb65cd363bfc 100644 (file)
@@ -699,6 +699,8 @@ static const struct sfp_upstream_ops qca807x_sfp_ops = {
        .detach = phy_sfp_detach,
        .module_insert = qca807x_sfp_insert,
        .module_remove = qca807x_sfp_remove,
+       .connect_phy = phy_sfp_connect_phy,
+       .disconnect_phy = phy_sfp_disconnect_phy,
 };
 
 static int qca807x_probe(struct phy_device *phydev)
index 8c848c79b1fda6ebd46ff17c511c72e3af000836..3ddfe7fe781aac13571fc9585946fba05a281031 100644 (file)
@@ -1758,6 +1758,8 @@ int phy_suspend(struct phy_device *phydev);
 int phy_resume(struct phy_device *phydev);
 int __phy_resume(struct phy_device *phydev);
 int phy_loopback(struct phy_device *phydev, bool enable);
+int phy_sfp_connect_phy(void *upstream, struct phy_device *phy);
+void phy_sfp_disconnect_phy(void *upstream, struct phy_device *phy);
 void phy_sfp_attach(void *upstream, struct sfp_bus *bus);
 void phy_sfp_detach(void *upstream, struct sfp_bus *bus);
 int phy_sfp_probe(struct phy_device *phydev,