mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
3849687869
Link topologies containing multiple network PHYs attached to the same net_device can be found when using a PHY as a media converter for use with an SFP connector, on which an SFP transceiver containing a PHY can be used. With the current model, the transceiver's PHY can't be used for operations such as cable testing, timestamping, macsec offload, etc. The reason being that most of the logic for these configuration, coming from either ethtool netlink or ioctls tend to use netdev->phydev, which in multi-phy systems will reference the PHY closest to the MAC. Introduce a numbering scheme allowing to enumerate PHY devices that belong to any netdev, which can in turn allow userspace to take more precise decisions with regard to each PHY's configuration. The numbering is maintained per-netdev, in a phy_device_list. The numbering works similarly to a netdevice's ifindex, with identifiers that are only recycled once INT_MAX has been reached. This prevents races that could occur between PHY listing and SFP transceiver removal/insertion. The identifiers are assigned at phy_attach time, as the numbering depends on the netdevice the phy is attached to. The PHY index can be re-used for PHYs that are persistent. Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com> Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu> Tested-by: Christophe Leroy <christophe.leroy@csgroup.eu> Signed-off-by: David S. Miller <davem@davemloft.net>
83 lines
1.7 KiB
C
83 lines
1.7 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* PHY device list allow maintaining a list of PHY devices that are
|
|
* part of a netdevice's link topology. PHYs can for example be chained,
|
|
* as is the case when using a PHY that exposes an SFP module, on which an
|
|
* SFP transceiver that embeds a PHY is connected.
|
|
*
|
|
* This list can then be used by userspace to leverage individual PHY
|
|
* capabilities.
|
|
*/
|
|
#ifndef __PHY_LINK_TOPOLOGY_H
|
|
#define __PHY_LINK_TOPOLOGY_H
|
|
|
|
#include <linux/ethtool.h>
|
|
#include <linux/netdevice.h>
|
|
|
|
struct xarray;
|
|
struct phy_device;
|
|
struct sfp_bus;
|
|
|
|
struct phy_link_topology {
|
|
struct xarray phys;
|
|
u32 next_phy_index;
|
|
};
|
|
|
|
struct phy_device_node {
|
|
enum phy_upstream upstream_type;
|
|
|
|
union {
|
|
struct net_device *netdev;
|
|
struct phy_device *phydev;
|
|
} upstream;
|
|
|
|
struct sfp_bus *parent_sfp_bus;
|
|
|
|
struct phy_device *phy;
|
|
};
|
|
|
|
#if IS_ENABLED(CONFIG_PHYLIB)
|
|
int phy_link_topo_add_phy(struct net_device *dev,
|
|
struct phy_device *phy,
|
|
enum phy_upstream upt, void *upstream);
|
|
|
|
void phy_link_topo_del_phy(struct net_device *dev, struct phy_device *phy);
|
|
|
|
static inline struct phy_device *
|
|
phy_link_topo_get_phy(struct net_device *dev, u32 phyindex)
|
|
{
|
|
struct phy_link_topology *topo = dev->link_topo;
|
|
struct phy_device_node *pdn;
|
|
|
|
if (!topo)
|
|
return NULL;
|
|
|
|
pdn = xa_load(&topo->phys, phyindex);
|
|
if (pdn)
|
|
return pdn->phy;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#else
|
|
static inline int phy_link_topo_add_phy(struct net_device *dev,
|
|
struct phy_device *phy,
|
|
enum phy_upstream upt, void *upstream)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void phy_link_topo_del_phy(struct net_device *dev,
|
|
struct phy_device *phy)
|
|
{
|
|
}
|
|
|
|
static inline struct phy_device *
|
|
phy_link_topo_get_phy(struct net_device *dev, u32 phyindex)
|
|
{
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
#endif /* __PHY_LINK_TOPOLOGY_H */
|