1 // SPDX-License-Identifier: GPL-2.0+
3 * Infrastructure to handle all PHY devices connected to a given netdev,
4 * either directly or indirectly attached.
6 * Copyright (c) 2023 Maxime Chevallier<maxime.chevallier@bootlin.com>
9 #include <linux/phy_link_topology.h>
10 #include <linux/phy.h>
11 #include <linux/rtnetlink.h>
12 #include <linux/xarray.h>
14 static int netdev_alloc_phy_link_topology(struct net_device
*dev
)
16 struct phy_link_topology
*topo
;
18 topo
= kzalloc(sizeof(*topo
), GFP_KERNEL
);
22 xa_init_flags(&topo
->phys
, XA_FLAGS_ALLOC1
);
23 topo
->next_phy_index
= 1;
25 dev
->link_topo
= topo
;
30 int phy_link_topo_add_phy(struct net_device
*dev
,
31 struct phy_device
*phy
,
32 enum phy_upstream upt
, void *upstream
)
34 struct phy_link_topology
*topo
= dev
->link_topo
;
35 struct phy_device_node
*pdn
;
39 ret
= netdev_alloc_phy_link_topology(dev
);
43 topo
= dev
->link_topo
;
46 pdn
= kzalloc(sizeof(*pdn
), GFP_KERNEL
);
52 case PHY_UPSTREAM_MAC
:
53 pdn
->upstream
.netdev
= (struct net_device
*)upstream
;
55 pdn
->parent_sfp_bus
= pdn
->upstream
.netdev
->sfp_bus
;
57 case PHY_UPSTREAM_PHY
:
58 pdn
->upstream
.phydev
= (struct phy_device
*)upstream
;
60 pdn
->parent_sfp_bus
= pdn
->upstream
.phydev
->sfp_bus
;
66 pdn
->upstream_type
= upt
;
68 /* Attempt to re-use a previously allocated phy_index */
70 ret
= xa_insert(&topo
->phys
, phy
->phyindex
, pdn
, GFP_KERNEL
);
72 ret
= xa_alloc_cyclic(&topo
->phys
, &phy
->phyindex
, pdn
,
73 xa_limit_32b
, &topo
->next_phy_index
,
85 EXPORT_SYMBOL_GPL(phy_link_topo_add_phy
);
87 void phy_link_topo_del_phy(struct net_device
*dev
,
88 struct phy_device
*phy
)
90 struct phy_link_topology
*topo
= dev
->link_topo
;
91 struct phy_device_node
*pdn
;
96 pdn
= xa_erase(&topo
->phys
, phy
->phyindex
);
98 /* We delete the PHY from the topology, however we don't re-set the
99 * phy->phyindex field. If the PHY isn't gone, we can re-assign it the
100 * same index next time it's added back to the topology
105 EXPORT_SYMBOL_GPL(phy_link_topo_del_phy
);