summaryrefslogtreecommitdiff
path: root/drivers/net/phy/mdio_devres.c
diff options
context:
space:
mode:
authorBartosz Golaszewski <bgolaszewski@baylibre.com>2020-06-29 14:03:43 +0200
committerDavid S. Miller <davem@davemloft.net>2020-06-30 15:57:34 -0700
commitac3a68d56651c3dad2c12c7afce065fe15267f44 (patch)
tree71ed3ea13a53ccae6483acae6caa4b53c29d32d6 /drivers/net/phy/mdio_devres.c
parent6a9a5723cb2ef3cdf3604e9f0c63c8e68cbb08d5 (diff)
net: phy: don't abuse devres in devm_mdiobus_register()
We currently have two managed helpers for mdiobus - devm_mdiobus_alloc() and devm_mdiobus_register(). The idea behind devres is that the release callback releases whatever resource the devm function allocates. In the mdiobus case however there's no devres associated with the device by devm_mdiobus_register(). Instead the release callback for devm_mdiobus_alloc(): _devm_mdiobus_free() unregisters the device if it is marked as managed. This all seems wrong. The managed structure shouldn't need to know or care about whether it's managed or not - and this is the case now for struct mii_bus. The devres wrapper should be opaque to the managed resource. This changeset makes devm_mdiobus_alloc() and devm_mdiobus_register() conform to common devres standards: devm_mdiobus_alloc() allocates a devres structure and registers a callback that will call mdiobus_free(). __devm_mdiobus_register() allocated another devres and registers a callback that will unregister the bus. Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy/mdio_devres.c')
-rw-r--r--drivers/net/phy/mdio_devres.c83
1 files changed, 77 insertions, 6 deletions
diff --git a/drivers/net/phy/mdio_devres.c b/drivers/net/phy/mdio_devres.c
index 3ee887733d4a..0b9bd9a61378 100644
--- a/drivers/net/phy/mdio_devres.c
+++ b/drivers/net/phy/mdio_devres.c
@@ -1,25 +1,96 @@
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/device.h>
#include <linux/phy.h>
+#include <linux/stddef.h>
+
+struct mdiobus_devres {
+ struct mii_bus *mii;
+};
+
+static void devm_mdiobus_free(struct device *dev, void *this)
+{
+ struct mdiobus_devres *dr = this;
+
+ mdiobus_free(dr->mii);
+}
+
+/**
+ * devm_mdiobus_alloc_size - Resource-managed mdiobus_alloc_size()
+ * @dev: Device to allocate mii_bus for
+ * @sizeof_priv: Space to allocate for private structure
+ *
+ * Managed mdiobus_alloc_size. mii_bus allocated with this function is
+ * automatically freed on driver detach.
+ *
+ * RETURNS:
+ * Pointer to allocated mii_bus on success, NULL on out-of-memory error.
+ */
+struct mii_bus *devm_mdiobus_alloc_size(struct device *dev, int sizeof_priv)
+{
+ struct mdiobus_devres *dr;
+
+ dr = devres_alloc(devm_mdiobus_free, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return NULL;
+
+ dr->mii = mdiobus_alloc_size(sizeof_priv);
+ if (!dr->mii) {
+ devres_free(dr);
+ return NULL;
+ }
+
+ devres_add(dev, dr);
+ return dr->mii;
+}
+EXPORT_SYMBOL(devm_mdiobus_alloc_size);
+
+static void devm_mdiobus_unregister(struct device *dev, void *this)
+{
+ struct mdiobus_devres *dr = this;
+
+ mdiobus_unregister(dr->mii);
+}
+
+static int mdiobus_devres_match(struct device *dev,
+ void *this, void *match_data)
+{
+ struct mdiobus_devres *res = this;
+ struct mii_bus *mii = match_data;
+
+ return mii == res->mii;
+}
/**
* __devm_mdiobus_register - Resource-managed variant of mdiobus_register()
+ * @dev: Device to register mii_bus for
* @bus: MII bus structure to register
* @owner: Owning module
*
* Returns 0 on success, negative error number on failure.
*/
-int __devm_mdiobus_register(struct mii_bus *bus, struct module *owner)
+int __devm_mdiobus_register(struct device *dev, struct mii_bus *bus,
+ struct module *owner)
{
+ struct mdiobus_devres *dr;
int ret;
- if (!bus->is_managed)
- return -EPERM;
+ if (WARN_ON(!devres_find(dev, devm_mdiobus_free,
+ mdiobus_devres_match, bus)))
+ return -EINVAL;
+
+ dr = devres_alloc(devm_mdiobus_unregister, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
ret = __mdiobus_register(bus, owner);
- if (!ret)
- bus->is_managed_registered = 1;
+ if (ret) {
+ devres_free(dr);
+ return ret;
+ }
- return ret;
+ dr->mii = bus;
+ devres_add(dev, dr);
+ return 0;
}
EXPORT_SYMBOL(__devm_mdiobus_register);