net: pcs: xpcs: add xpcs_create_mdiodev()
authorRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Fri, 26 May 2023 10:14:29 +0000 (11:14 +0100)
committerJakub Kicinski <kuba@kernel.org>
Tue, 30 May 2023 04:46:53 +0000 (21:46 -0700)
Add xpcs_create_mdiodev() to simplify the creation of the mdio device
associated with the XPCS. In order to allow xpcs_destroy() to clean
this up, we need to arrange for xpcs_create() to take a refcount on
the mdiodev, and xpcs_destroy() to put it.

Adding the refcounting to xpcs_create()..xpcs_destroy() will be
transparent to existing users of these interfaces.

Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/pcs/pcs-xpcs.c
include/linux/pcs/pcs-xpcs.h

index 736776e40c25661feeda16f9754ef5124934147e..1ba214429e012620c3a96431eceb95e902efe1e2 100644 (file)
@@ -1235,6 +1235,7 @@ struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
        if (!xpcs)
                return ERR_PTR(-ENOMEM);
 
+       mdio_device_get(mdiodev);
        xpcs->mdiodev = mdiodev;
 
        xpcs_id = xpcs_get_id(xpcs);
@@ -1267,6 +1268,7 @@ struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
        ret = -ENODEV;
 
 out:
+       mdio_device_put(mdiodev);
        kfree(xpcs);
 
        return ERR_PTR(ret);
@@ -1275,8 +1277,34 @@ EXPORT_SYMBOL_GPL(xpcs_create);
 
 void xpcs_destroy(struct dw_xpcs *xpcs)
 {
+       if (xpcs)
+               mdio_device_put(xpcs->mdiodev);
        kfree(xpcs);
 }
 EXPORT_SYMBOL_GPL(xpcs_destroy);
 
+struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr,
+                                   phy_interface_t interface)
+{
+       struct mdio_device *mdiodev;
+       struct dw_xpcs *xpcs;
+
+       mdiodev = mdio_device_create(bus, addr);
+       if (IS_ERR(mdiodev))
+               return ERR_CAST(mdiodev);
+
+       xpcs = xpcs_create(mdiodev, interface);
+
+       /* xpcs_create() has taken a refcount on the mdiodev if it was
+        * successful. If xpcs_create() fails, this will free the mdio
+        * device here. In any case, we don't need to hold our reference
+        * anymore, and putting it here will allow mdio_device_put() in
+        * xpcs_destroy() to automatically free the mdio device.
+        */
+       mdio_device_put(mdiodev);
+
+       return xpcs;
+}
+EXPORT_SYMBOL_GPL(xpcs_create_mdiodev);
+
 MODULE_LICENSE("GPL v2");
index d2da1e0b4a92ba8ab7e530adceb5d777c65fc3fe..a99972a6d0461a126babea1604196edf944aa813 100644 (file)
@@ -37,6 +37,8 @@ int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns,
                    int enable);
 struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
                            phy_interface_t interface);
+struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr,
+                                   phy_interface_t interface);
 void xpcs_destroy(struct dw_xpcs *xpcs);
 
 #endif /* __LINUX_PCS_XPCS_H */