xref: /linux/drivers/net/phy/phy_link_topology.c (revision 3e64db35bc37edbe9e37aaa987df92cde12ddb6c)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Infrastructure to handle all PHY devices connected to a given netdev,
4  * either directly or indirectly attached.
5  *
6  * Copyright (c) 2023 Maxime Chevallier<maxime.chevallier@bootlin.com>
7  */
8 
9 #include <linux/phy_link_topology.h>
10 #include <linux/netdevice.h>
11 #include <linux/phy.h>
12 #include <linux/rtnetlink.h>
13 #include <linux/xarray.h>
14 
15 int phy_link_topo_add_phy(struct phy_link_topology *topo,
16 			  struct phy_device *phy,
17 			  enum phy_upstream upt, void *upstream)
18 {
19 	struct phy_device_node *pdn;
20 	int ret;
21 
22 	pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
23 	if (!pdn)
24 		return -ENOMEM;
25 
26 	pdn->phy = phy;
27 	switch (upt) {
28 	case PHY_UPSTREAM_MAC:
29 		pdn->upstream.netdev = (struct net_device *)upstream;
30 		if (phy_on_sfp(phy))
31 			pdn->parent_sfp_bus = pdn->upstream.netdev->sfp_bus;
32 		break;
33 	case PHY_UPSTREAM_PHY:
34 		pdn->upstream.phydev = (struct phy_device *)upstream;
35 		if (phy_on_sfp(phy))
36 			pdn->parent_sfp_bus = pdn->upstream.phydev->sfp_bus;
37 		break;
38 	default:
39 		ret = -EINVAL;
40 		goto err;
41 	}
42 	pdn->upstream_type = upt;
43 
44 	ret = xa_alloc_cyclic(&topo->phys, &phy->phyindex, pdn, xa_limit_32b,
45 			      &topo->next_phy_index, GFP_KERNEL);
46 	if (ret)
47 		goto err;
48 
49 	return 0;
50 
51 err:
52 	kfree(pdn);
53 	return ret;
54 }
55 EXPORT_SYMBOL_GPL(phy_link_topo_add_phy);
56 
57 void phy_link_topo_del_phy(struct phy_link_topology *topo,
58 			   struct phy_device *phy)
59 {
60 	struct phy_device_node *pdn = xa_erase(&topo->phys, phy->phyindex);
61 
62 	phy->phyindex = 0;
63 
64 	kfree(pdn);
65 }
66 EXPORT_SYMBOL_GPL(phy_link_topo_del_phy);
67