From 09ef193fef7efb0175a04634853862d717adbb95 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 29 Jun 2020 14:03:37 +0200 Subject: [PATCH 01/10] net: ethernet: ixgbe: check the return value of ixgbe_mii_bus_init() This function may fail. Check its return value and propagate the error code. Signed-off-by: Bartosz Golaszewski Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 254486e6b09d2..fabdca9aadaef 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -11173,10 +11173,14 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL, true); - ixgbe_mii_bus_init(hw); + err = ixgbe_mii_bus_init(hw); + if (err) + goto err_netdev; return 0; +err_netdev: + unregister_netdev(netdev); err_register: ixgbe_release_hw_control(adapter); ixgbe_clear_interrupt_scheme(adapter); From d10d607f504bc7d0a6f69867a8eef0daa453dab7 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 29 Jun 2020 14:03:38 +0200 Subject: [PATCH 02/10] net: ethernet: ixgbe: don't call devm_mdiobus_free() The idea behind devres is that the release callbacks are called if probe fails. As we now check the return value of ixgbe_mii_bus_init(), we can drop the call devm_mdiobus_free() in error path as the release callback will be called automatically. Signed-off-by: Bartosz Golaszewski Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index 2fb97967961c4..7980d7265e106 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -905,7 +905,6 @@ s32 ixgbe_mii_bus_init(struct ixgbe_hw *hw) struct pci_dev *pdev = adapter->pdev; struct device *dev = &adapter->netdev->dev; struct mii_bus *bus; - int err = -ENODEV; bus = devm_mdiobus_alloc(dev); if (!bus) @@ -923,7 +922,7 @@ s32 ixgbe_mii_bus_init(struct ixgbe_hw *hw) case IXGBE_DEV_ID_X550EM_A_1G_T: case IXGBE_DEV_ID_X550EM_A_1G_T_L: if (!ixgbe_x550em_a_has_mii(hw)) - goto ixgbe_no_mii_bus; + return -ENODEV; bus->read = &ixgbe_x550em_a_mii_bus_read; bus->write = &ixgbe_x550em_a_mii_bus_write; break; @@ -948,15 +947,8 @@ s32 ixgbe_mii_bus_init(struct ixgbe_hw *hw) */ hw->phy.mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22; - err = mdiobus_register(bus); - if (!err) { - adapter->mii_bus = bus; - return 0; - } - -ixgbe_no_mii_bus: - devm_mdiobus_free(dev, bus); - return err; + adapter->mii_bus = bus; + return mdiobus_register(bus); } /** From fe189519e4d3ce655efa0bc64a6bed3f6f1ad1c2 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 29 Jun 2020 14:03:39 +0200 Subject: [PATCH 03/10] net: devres: rename the release callback of devm_register_netdev() Make it an explicit counterpart to devm_register_netdev() just like we do with devm_free_netdev() for better clarity. Signed-off-by: Bartosz Golaszewski Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/devres.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/devres.c b/net/devres.c index 57a6a88d11f65..1f9be2133787f 100644 --- a/net/devres.c +++ b/net/devres.c @@ -39,7 +39,7 @@ struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv, } EXPORT_SYMBOL(devm_alloc_etherdev_mqs); -static void devm_netdev_release(struct device *dev, void *this) +static void devm_unregister_netdev(struct device *dev, void *this) { struct net_device_devres *res = this; @@ -77,7 +77,7 @@ int devm_register_netdev(struct device *dev, struct net_device *ndev) netdev_devres_match, ndev))) return -EINVAL; - dr = devres_alloc(devm_netdev_release, sizeof(*dr), GFP_KERNEL); + dr = devres_alloc(devm_unregister_netdev, sizeof(*dr), GFP_KERNEL); if (!dr) return -ENOMEM; From bd8ff6de0cf5b05bc7e1822aec79edac05b02a35 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 29 Jun 2020 14:03:40 +0200 Subject: [PATCH 04/10] Documentation: devres: add missing mdio helper We have a devres variant of mdiobus_register() but it's not listed in devres.rst. Add it under other mdio devm functions. Signed-off-by: Bartosz Golaszewski Signed-off-by: David S. Miller --- Documentation/driver-api/driver-model/devres.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index e0b58c392e4f9..5463fc8a60c16 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -343,6 +343,7 @@ MDIO devm_mdiobus_alloc() devm_mdiobus_alloc_size() devm_mdiobus_free() + devm_mdiobus_register() MEM devm_free_pages() From 8b11c20a658de159fcf18ebce4f2acfdf747ff25 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 29 Jun 2020 14:03:41 +0200 Subject: [PATCH 05/10] phy: un-inline devm_mdiobus_register() Functions should only be static inline if they're very short. This devres helper is already over 10 lines and it will grow soon as we'll be improving upon its approach. Pull it into mdio_devres.c. Signed-off-by: Bartosz Golaszewski Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/Makefile | 2 +- drivers/net/phy/mdio_devres.c | 18 ++++++++++++++++++ include/linux/phy.h | 15 ++------------- 3 files changed, 21 insertions(+), 14 deletions(-) create mode 100644 drivers/net/phy/mdio_devres.c diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index dc9e53b511d6e..896afdcac4371 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -3,7 +3,7 @@ libphy-y := phy.o phy-c45.o phy-core.o phy_device.o \ linkmode.o -mdio-bus-y += mdio_bus.o mdio_device.o +mdio-bus-y += mdio_bus.o mdio_device.o mdio_devres.o ifdef CONFIG_MDIO_DEVICE obj-y += mdio-boardinfo.o diff --git a/drivers/net/phy/mdio_devres.c b/drivers/net/phy/mdio_devres.c new file mode 100644 index 0000000000000..f0b4b6cfe5e33 --- /dev/null +++ b/drivers/net/phy/mdio_devres.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +int __devm_mdiobus_register(struct mii_bus *bus, struct module *owner) +{ + int ret; + + if (!bus->is_managed) + return -EPERM; + + ret = __mdiobus_register(bus, owner); + if (!ret) + bus->is_managed_registered = 1; + + return ret; +} +EXPORT_SYMBOL(__devm_mdiobus_register); diff --git a/include/linux/phy.h b/include/linux/phy.h index ecc7640705b96..7c75e1c90141d 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -322,20 +322,9 @@ static inline struct mii_bus *mdiobus_alloc(void) } int __mdiobus_register(struct mii_bus *bus, struct module *owner); +int __devm_mdiobus_register(struct mii_bus *bus, struct module *owner); #define mdiobus_register(bus) __mdiobus_register(bus, THIS_MODULE) -static inline int devm_mdiobus_register(struct mii_bus *bus) -{ - int ret; - - if (!bus->is_managed) - return -EPERM; - - ret = mdiobus_register(bus); - if (!ret) - bus->is_managed_registered = 1; - - return ret; -} +#define devm_mdiobus_register(bus) __devm_mdiobus_register(bus, THIS_MODULE) void mdiobus_unregister(struct mii_bus *bus); void mdiobus_free(struct mii_bus *bus); From 6a9a5723cb2ef3cdf3604e9f0c63c8e68cbb08d5 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 29 Jun 2020 14:03:42 +0200 Subject: [PATCH 06/10] phy: mdio: add kerneldoc for __devm_mdiobus_register() This function is not documented. Add a short kerneldoc description. Signed-off-by: Bartosz Golaszewski Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/mdio_devres.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/phy/mdio_devres.c b/drivers/net/phy/mdio_devres.c index f0b4b6cfe5e33..3ee887733d4a5 100644 --- a/drivers/net/phy/mdio_devres.c +++ b/drivers/net/phy/mdio_devres.c @@ -2,6 +2,13 @@ #include +/** + * __devm_mdiobus_register - Resource-managed variant of mdiobus_register() + * @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 ret; From ac3a68d56651c3dad2c12c7afce065fe15267f44 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 29 Jun 2020 14:03:43 +0200 Subject: [PATCH 07/10] 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 Signed-off-by: David S. Miller --- .../driver-api/driver-model/devres.rst | 1 - drivers/net/ethernet/realtek/r8169_main.c | 2 +- drivers/net/phy/mdio_bus.c | 73 ---------------- drivers/net/phy/mdio_devres.c | 83 +++++++++++++++++-- include/linux/phy.h | 10 +-- 5 files changed, 82 insertions(+), 87 deletions(-) diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 5463fc8a60c16..e0333d66a7f4d 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -342,7 +342,6 @@ LED MDIO devm_mdiobus_alloc() devm_mdiobus_alloc_size() - devm_mdiobus_free() devm_mdiobus_register() MEM diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 07a33af1f64ea..745e1739e9c8a 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5012,7 +5012,7 @@ static int r8169_mdio_register(struct rtl8169_private *tp) new_bus->read = r8169_mdio_read_reg; new_bus->write = r8169_mdio_write_reg; - ret = devm_mdiobus_register(new_bus); + ret = devm_mdiobus_register(&pdev->dev, new_bus); if (ret) return ret; diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 134f82d72da80..46b33701ad4b0 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -165,79 +165,6 @@ struct mii_bus *mdiobus_alloc_size(size_t size) } EXPORT_SYMBOL(mdiobus_alloc_size); -static void _devm_mdiobus_free(struct device *dev, void *res) -{ - struct mii_bus *bus = *(struct mii_bus **)res; - - if (bus->is_managed_registered && bus->state == MDIOBUS_REGISTERED) - mdiobus_unregister(bus); - - mdiobus_free(bus); -} - -static int devm_mdiobus_match(struct device *dev, void *res, void *data) -{ - struct mii_bus **r = res; - - if (WARN_ON(!r || !*r)) - return 0; - - return *r == data; -} - -/** - * 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. - * - * If an mii_bus allocated with this function needs to be freed separately, - * devm_mdiobus_free() must be used. - * - * RETURNS: - * Pointer to allocated mii_bus on success, NULL on failure. - */ -struct mii_bus *devm_mdiobus_alloc_size(struct device *dev, int sizeof_priv) -{ - struct mii_bus **ptr, *bus; - - ptr = devres_alloc(_devm_mdiobus_free, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return NULL; - - /* use raw alloc_dr for kmalloc caller tracing */ - bus = mdiobus_alloc_size(sizeof_priv); - if (bus) { - *ptr = bus; - devres_add(dev, ptr); - bus->is_managed = 1; - } else { - devres_free(ptr); - } - - return bus; -} -EXPORT_SYMBOL_GPL(devm_mdiobus_alloc_size); - -/** - * devm_mdiobus_free - Resource-managed mdiobus_free() - * @dev: Device this mii_bus belongs to - * @bus: the mii_bus associated with the device - * - * Free mii_bus allocated with devm_mdiobus_alloc_size(). - */ -void devm_mdiobus_free(struct device *dev, struct mii_bus *bus) -{ - int rc; - - rc = devres_release(dev, _devm_mdiobus_free, - devm_mdiobus_match, bus); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_mdiobus_free); - /** * mdiobus_release - mii_bus device release callback * @d: the target struct device that contains the mii_bus diff --git a/drivers/net/phy/mdio_devres.c b/drivers/net/phy/mdio_devres.c index 3ee887733d4a5..0b9bd9a61378b 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 #include +#include + +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); diff --git a/include/linux/phy.h b/include/linux/phy.h index 7c75e1c90141d..101a48fa67509 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -261,9 +261,6 @@ struct mii_bus { int (*reset)(struct mii_bus *bus); struct mdio_bus_stats stats[PHY_MAX_ADDR]; - unsigned int is_managed:1; /* is device-managed */ - unsigned int is_managed_registered:1; - /* * A lock to ensure that only one thing can read/write * the MDIO bus at a time @@ -322,9 +319,11 @@ static inline struct mii_bus *mdiobus_alloc(void) } int __mdiobus_register(struct mii_bus *bus, struct module *owner); -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); #define mdiobus_register(bus) __mdiobus_register(bus, THIS_MODULE) -#define devm_mdiobus_register(bus) __devm_mdiobus_register(bus, THIS_MODULE) +#define devm_mdiobus_register(dev, bus) \ + __devm_mdiobus_register(dev, bus, THIS_MODULE) void mdiobus_unregister(struct mii_bus *bus); void mdiobus_free(struct mii_bus *bus); @@ -335,7 +334,6 @@ static inline struct mii_bus *devm_mdiobus_alloc(struct device *dev) } struct mii_bus *mdio_find_bus(const char *mdio_name); -void devm_mdiobus_free(struct device *dev, struct mii_bus *bus); struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr); #define PHY_INTERRUPT_DISABLED false From a0bd96f5aed2108505386733abe76f37362c2f50 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 29 Jun 2020 14:03:44 +0200 Subject: [PATCH 08/10] of: mdio: remove the 'extern' keyword from function declarations The 'extern' keyword in headers doesn't have any benefit. Remove them all from the of_mdio.h header. Signed-off-by: Bartosz Golaszewski Signed-off-by: David S. Miller --- include/linux/of_mdio.h | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h index 0f61a4ac6bcfb..ba8e157f24ad0 100644 --- a/include/linux/of_mdio.h +++ b/include/linux/of_mdio.h @@ -12,27 +12,26 @@ #include #if IS_ENABLED(CONFIG_OF_MDIO) -extern bool of_mdiobus_child_is_phy(struct device_node *child); -extern int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np); -extern struct phy_device *of_phy_find_device(struct device_node *phy_np); -extern struct phy_device *of_phy_connect(struct net_device *dev, - struct device_node *phy_np, - void (*hndlr)(struct net_device *), - u32 flags, phy_interface_t iface); -extern struct phy_device * +bool of_mdiobus_child_is_phy(struct device_node *child); +int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np); +struct phy_device *of_phy_find_device(struct device_node *phy_np); +struct phy_device * +of_phy_connect(struct net_device *dev, struct device_node *phy_np, + void (*hndlr)(struct net_device *), u32 flags, + phy_interface_t iface); +struct phy_device * of_phy_get_and_connect(struct net_device *dev, struct device_node *np, void (*hndlr)(struct net_device *)); -struct phy_device *of_phy_attach(struct net_device *dev, - struct device_node *phy_np, u32 flags, - phy_interface_t iface); - -extern struct mii_bus *of_mdio_find_bus(struct device_node *mdio_np); -extern int of_phy_register_fixed_link(struct device_node *np); -extern void of_phy_deregister_fixed_link(struct device_node *np); -extern bool of_phy_is_fixed_link(struct device_node *np); -extern int of_mdiobus_phy_device_register(struct mii_bus *mdio, - struct phy_device *phy, - struct device_node *child, u32 addr); +struct phy_device * +of_phy_attach(struct net_device *dev, struct device_node *phy_np, + u32 flags, phy_interface_t iface); + +struct mii_bus *of_mdio_find_bus(struct device_node *mdio_np); +int of_phy_register_fixed_link(struct device_node *np); +void of_phy_deregister_fixed_link(struct device_node *np); +bool of_phy_is_fixed_link(struct device_node *np); +int of_mdiobus_phy_device_register(struct mii_bus *mdio, struct phy_device *phy, + struct device_node *child, u32 addr); static inline int of_mdio_parse_addr(struct device *dev, const struct device_node *np) From 14eeb6e086d6b9004c600e5f0f62bacb458ecfba Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 29 Jun 2020 14:03:45 +0200 Subject: [PATCH 09/10] of: mdio: provide devm_of_mdiobus_register() Implement a managed variant of of_mdiobus_register(). We need to make mdio_devres into its own module because otherwise we'd hit circular sumbol dependencies between phylib and of_mdio. Signed-off-by: Bartosz Golaszewski Signed-off-by: David S. Miller --- .../driver-api/driver-model/devres.rst | 1 + drivers/net/phy/Makefile | 4 +- drivers/net/phy/mdio_devres.c | 37 +++++++++++++++++++ include/linux/of_mdio.h | 3 ++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index e0333d66a7f4d..eaaaafc21134f 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -343,6 +343,7 @@ MDIO devm_mdiobus_alloc() devm_mdiobus_alloc_size() devm_mdiobus_register() + devm_of_mdiobus_register() MEM devm_free_pages() diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 896afdcac4371..c9a9adf194d50 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -3,7 +3,8 @@ libphy-y := phy.o phy-c45.o phy-core.o phy_device.o \ linkmode.o -mdio-bus-y += mdio_bus.o mdio_device.o mdio_devres.o +mdio-bus-y += mdio_bus.o mdio_device.o +mdio-devres-y += mdio_devres.o ifdef CONFIG_MDIO_DEVICE obj-y += mdio-boardinfo.o @@ -17,6 +18,7 @@ libphy-y += $(mdio-bus-y) else obj-$(CONFIG_MDIO_DEVICE) += mdio-bus.o endif +obj-$(CONFIG_MDIO_DEVICE) += mdio-devres.o libphy-$(CONFIG_SWPHY) += swphy.o libphy-$(CONFIG_LED_TRIGGER_PHY) += phy_led_triggers.o diff --git a/drivers/net/phy/mdio_devres.c b/drivers/net/phy/mdio_devres.c index 0b9bd9a61378b..b560e99695dfd 100644 --- a/drivers/net/phy/mdio_devres.c +++ b/drivers/net/phy/mdio_devres.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include #include @@ -94,3 +95,39 @@ int __devm_mdiobus_register(struct device *dev, struct mii_bus *bus, return 0; } EXPORT_SYMBOL(__devm_mdiobus_register); + +#if IS_ENABLED(CONFIG_OF_MDIO) +/** + * devm_of_mdiobus_register - Resource managed variant of of_mdiobus_register() + * @dev: Device to register mii_bus for + * @mdio: MII bus structure to register + * @np: Device node to parse + */ +int devm_of_mdiobus_register(struct device *dev, struct mii_bus *mdio, + struct device_node *np) +{ + struct mdiobus_devres *dr; + int ret; + + if (WARN_ON(!devres_find(dev, devm_mdiobus_free, + mdiobus_devres_match, mdio))) + return -EINVAL; + + dr = devres_alloc(devm_mdiobus_unregister, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + ret = of_mdiobus_register(mdio, np); + if (ret) { + devres_free(dr); + return ret; + } + + dr->mii = mdio; + devres_add(dev, dr); + return 0; +} +EXPORT_SYMBOL(devm_of_mdiobus_register); +#endif /* CONFIG_OF_MDIO */ + +MODULE_LICENSE("GPL"); diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h index ba8e157f24ad0..1efb88d9f8928 100644 --- a/include/linux/of_mdio.h +++ b/include/linux/of_mdio.h @@ -8,12 +8,15 @@ #ifndef __LINUX_OF_MDIO_H #define __LINUX_OF_MDIO_H +#include #include #include #if IS_ENABLED(CONFIG_OF_MDIO) bool of_mdiobus_child_is_phy(struct device_node *child); int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np); +int devm_of_mdiobus_register(struct device *dev, struct mii_bus *mdio, + struct device_node *np); struct phy_device *of_phy_find_device(struct device_node *phy_np); struct phy_device * of_phy_connect(struct net_device *dev, struct device_node *phy_np, From 9ed0a3fac08bddaf104038b6371eaa6494c6fd83 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 29 Jun 2020 14:03:46 +0200 Subject: [PATCH 10/10] net: ethernet: mtk-star-emac: use devm_of_mdiobus_register() Shrink the code by using the managed variant of of_mdiobus_register(). Signed-off-by: Bartosz Golaszewski Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_star_emac.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_star_emac.c b/drivers/net/ethernet/mediatek/mtk_star_emac.c index 3e765bdcf9e12..13250553263b5 100644 --- a/drivers/net/ethernet/mediatek/mtk_star_emac.c +++ b/drivers/net/ethernet/mediatek/mtk_star_emac.c @@ -1389,7 +1389,7 @@ static int mtk_star_mdio_init(struct net_device *ndev) priv->mii->write = mtk_star_mdio_write; priv->mii->priv = priv; - ret = of_mdiobus_register(priv->mii, mdio_node); + ret = devm_of_mdiobus_register(dev, priv->mii, mdio_node); out_put_node: of_node_put(mdio_node); @@ -1441,13 +1441,6 @@ static void mtk_star_clk_disable_unprepare(void *data) clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks); } -static void mtk_star_mdiobus_unregister(void *data) -{ - struct mtk_star_priv *priv = data; - - mdiobus_unregister(priv->mii); -} - static int mtk_star_probe(struct platform_device *pdev) { struct device_node *of_node; @@ -1549,10 +1542,6 @@ static int mtk_star_probe(struct platform_device *pdev) if (ret) return ret; - ret = devm_add_action_or_reset(dev, mtk_star_mdiobus_unregister, priv); - if (ret) - return ret; - ret = eth_platform_get_mac_address(dev, ndev->dev_addr); if (ret || !is_valid_ether_addr(ndev->dev_addr)) eth_hw_addr_random(ndev);