Commit 471e8fd3 authored by Christian Marangi's avatar Christian Marangi Committed by David S. Miller

net: phy: add devm/of_phy_package_join helper

Add devm/of_phy_package_join helper to join PHYs in a PHY package. These
are variant of the manual phy_package_join with the difference that
these will use DT nodes to derive the base_addr instead of manually
passing an hardcoded value.

An additional value is added in phy_package_shared, "np" to reference
the PHY package node pointer in specific PHY driver probe_once and
config_init_once functions to make use of additional specific properties
defined in the PHY package node in DT.

The np value is filled only with of_phy_package_join if a valid PHY
package node is found. A valid PHY package node must have the node name
set to "ethernet-phy-package".
Signed-off-by: default avatarChristian Marangi <ansuelsmth@gmail.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 385ef48f
...@@ -1712,6 +1712,7 @@ int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size) ...@@ -1712,6 +1712,7 @@ int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size)
shared->priv_size = priv_size; shared->priv_size = priv_size;
} }
shared->base_addr = base_addr; shared->base_addr = base_addr;
shared->np = NULL;
refcount_set(&shared->refcnt, 1); refcount_set(&shared->refcnt, 1);
bus->shared[base_addr] = shared; bus->shared[base_addr] = shared;
} else { } else {
...@@ -1734,6 +1735,63 @@ int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size) ...@@ -1734,6 +1735,63 @@ int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size)
} }
EXPORT_SYMBOL_GPL(phy_package_join); EXPORT_SYMBOL_GPL(phy_package_join);
/**
* of_phy_package_join - join a common PHY group in PHY package
* @phydev: target phy_device struct
* @priv_size: if non-zero allocate this amount of bytes for private data
*
* This is a variant of phy_package_join for PHY package defined in DT.
*
* The parent node of the @phydev is checked as a valid PHY package node
* structure (by matching the node name "ethernet-phy-package") and the
* base_addr for the PHY package is passed to phy_package_join.
*
* With this configuration the shared struct will also have the np value
* filled to use additional DT defined properties in PHY specific
* probe_once and config_init_once PHY package OPs.
*
* Returns < 0 on error, 0 on success. Esp. calling phy_package_join()
* with the same cookie but a different priv_size is an error. Or a parent
* node is not detected or is not valid or doesn't match the expected node
* name for PHY package.
*/
int of_phy_package_join(struct phy_device *phydev, size_t priv_size)
{
struct device_node *node = phydev->mdio.dev.of_node;
struct device_node *package_node;
u32 base_addr;
int ret;
if (!node)
return -EINVAL;
package_node = of_get_parent(node);
if (!package_node)
return -EINVAL;
if (!of_node_name_eq(package_node, "ethernet-phy-package")) {
ret = -EINVAL;
goto exit;
}
if (of_property_read_u32(package_node, "reg", &base_addr)) {
ret = -EINVAL;
goto exit;
}
ret = phy_package_join(phydev, base_addr, priv_size);
if (ret)
goto exit;
phydev->shared->np = package_node;
return 0;
exit:
of_node_put(package_node);
return ret;
}
EXPORT_SYMBOL_GPL(of_phy_package_join);
/** /**
* phy_package_leave - leave a common PHY group * phy_package_leave - leave a common PHY group
* @phydev: target phy_device struct * @phydev: target phy_device struct
...@@ -1750,6 +1808,10 @@ void phy_package_leave(struct phy_device *phydev) ...@@ -1750,6 +1808,10 @@ void phy_package_leave(struct phy_device *phydev)
if (!shared) if (!shared)
return; return;
/* Decrease the node refcount on leave if present */
if (shared->np)
of_node_put(shared->np);
if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) { if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
bus->shared[shared->base_addr] = NULL; bus->shared[shared->base_addr] = NULL;
mutex_unlock(&bus->shared_lock); mutex_unlock(&bus->shared_lock);
...@@ -1802,6 +1864,40 @@ int devm_phy_package_join(struct device *dev, struct phy_device *phydev, ...@@ -1802,6 +1864,40 @@ int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
} }
EXPORT_SYMBOL_GPL(devm_phy_package_join); EXPORT_SYMBOL_GPL(devm_phy_package_join);
/**
* devm_of_phy_package_join - resource managed of_phy_package_join()
* @dev: device that is registering this PHY package
* @phydev: target phy_device struct
* @priv_size: if non-zero allocate this amount of bytes for private data
*
* Managed of_phy_package_join(). Shared storage fetched by this function,
* phy_package_leave() is automatically called on driver detach. See
* of_phy_package_join() for more information.
*/
int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,
size_t priv_size)
{
struct phy_device **ptr;
int ret;
ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr),
GFP_KERNEL);
if (!ptr)
return -ENOMEM;
ret = of_phy_package_join(phydev, priv_size);
if (!ret) {
*ptr = phydev;
devres_add(dev, ptr);
} else {
devres_free(ptr);
}
return ret;
}
EXPORT_SYMBOL_GPL(devm_of_phy_package_join);
/** /**
* phy_detach - detach a PHY device from its network device * phy_detach - detach a PHY device from its network device
* @phydev: target phy_device struct * @phydev: target phy_device struct
......
...@@ -329,6 +329,7 @@ struct mdio_bus_stats { ...@@ -329,6 +329,7 @@ struct mdio_bus_stats {
* struct phy_package_shared - Shared information in PHY packages * struct phy_package_shared - Shared information in PHY packages
* @base_addr: Base PHY address of PHY package used to combine PHYs * @base_addr: Base PHY address of PHY package used to combine PHYs
* in one package and for offset calculation of phy_package_read/write * in one package and for offset calculation of phy_package_read/write
* @np: Pointer to the Device Node if PHY package defined in DT
* @refcnt: Number of PHYs connected to this shared data * @refcnt: Number of PHYs connected to this shared data
* @flags: Initialization of PHY package * @flags: Initialization of PHY package
* @priv_size: Size of the shared private data @priv * @priv_size: Size of the shared private data @priv
...@@ -340,6 +341,8 @@ struct mdio_bus_stats { ...@@ -340,6 +341,8 @@ struct mdio_bus_stats {
*/ */
struct phy_package_shared { struct phy_package_shared {
u8 base_addr; u8 base_addr;
/* With PHY package defined in DT this points to the PHY package node */
struct device_node *np;
refcount_t refcnt; refcount_t refcnt;
unsigned long flags; unsigned long flags;
size_t priv_size; size_t priv_size;
...@@ -2000,9 +2003,12 @@ int phy_ethtool_set_link_ksettings(struct net_device *ndev, ...@@ -2000,9 +2003,12 @@ int phy_ethtool_set_link_ksettings(struct net_device *ndev,
const struct ethtool_link_ksettings *cmd); const struct ethtool_link_ksettings *cmd);
int phy_ethtool_nway_reset(struct net_device *ndev); int phy_ethtool_nway_reset(struct net_device *ndev);
int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size); int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size);
int of_phy_package_join(struct phy_device *phydev, size_t priv_size);
void phy_package_leave(struct phy_device *phydev); void phy_package_leave(struct phy_device *phydev);
int devm_phy_package_join(struct device *dev, struct phy_device *phydev, int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
int base_addr, size_t priv_size); int base_addr, size_t priv_size);
int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,
size_t priv_size);
int __init mdio_bus_init(void); int __init mdio_bus_init(void);
void mdio_bus_exit(void); void mdio_bus_exit(void);
......
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