Commit 2429ec26 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-improve-devres-helpers'

Bartosz Golaszewski says:

====================
net: improve devres helpers

So it seems like there's no support for relaxing certain networking devres
helpers to not require previously allocated structures to also be managed.
However the way mdio devres variants are implemented is still wrong and I
modified my series to address it while keeping the functions strict.

First two patches modify the ixgbe driver to get rid of the last user of
devm_mdiobus_free().

Patches 3, 4, 5 and 6 are mostly cosmetic.

Patch 7 fixes the way devm_mdiobus_register() is implemented.

Patches 8 & 9 provide a managed variant of of_mdiobus_register() and
last patch uses it in mtk-star-emac driver.

v1 -> v2:
- drop the patch relaxing devm_register_netdev()
- require struct mii_bus to be managed in devm_mdiobus_register() and
  devm_of_mdiobus_register() but don't store that information in the
  structure itself: use devres_find() instead
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e0cdac65 9ed0a3fa
......@@ -342,7 +342,8 @@ LED
MDIO
devm_mdiobus_alloc()
devm_mdiobus_alloc_size()
devm_mdiobus_free()
devm_mdiobus_register()
devm_of_mdiobus_register()
MEM
devm_free_pages()
......
......@@ -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);
......
......@@ -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);
}
/**
......
......@@ -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);
......
......@@ -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;
......
......@@ -4,6 +4,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-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
......
......@@ -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
......
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/device.h>
#include <linux/of_mdio.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 device *dev, struct mii_bus *bus,
struct module *owner)
{
struct mdiobus_devres *dr;
int ret;
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) {
devres_free(dr);
return ret;
}
dr->mii = bus;
devres_add(dev, dr);
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");
......@@ -8,31 +8,33 @@
#ifndef __LINUX_OF_MDIO_H
#define __LINUX_OF_MDIO_H
#include <linux/device.h>
#include <linux/phy.h>
#include <linux/of.h>
#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);
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,
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)
......
......@@ -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,20 +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 device *dev, 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(dev, bus) \
__devm_mdiobus_register(dev, bus, THIS_MODULE)
void mdiobus_unregister(struct mii_bus *bus);
void mdiobus_free(struct mii_bus *bus);
......@@ -346,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
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment