xref: /linux/drivers/net/phy/phy_link_topology.c (revision 2d7eaeb05ae265bd64270376e6a2c0d80244771f)
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/phy_port.h>
11 #include <linux/phy.h>
12 #include <linux/rtnetlink.h>
13 #include <linux/xarray.h>
14 #include <net/netdev_lock.h>
15 
16 static int netdev_alloc_phy_link_topology(struct net_device *dev)
17 {
18 	struct phy_link_topology *topo;
19 
20 	topo = kzalloc_obj(*topo);
21 	if (!topo)
22 		return -ENOMEM;
23 
24 	xa_init_flags(&topo->phys, XA_FLAGS_ALLOC1);
25 	topo->next_phy_index = 1;
26 
27 	xa_init_flags(&topo->ports, XA_FLAGS_ALLOC1);
28 	topo->next_port_index = 1;
29 
30 	dev->link_topo = topo;
31 
32 	return 0;
33 }
34 
35 static struct phy_link_topology *phy_link_topo_get_or_alloc(struct net_device *dev)
36 {
37 	int ret;
38 
39 	if (dev->link_topo)
40 		return dev->link_topo;
41 
42 	/* The topology is allocated the first time we add an object to it.
43 	 * It is freed alongside the netdev. It can be called on multiple
44 	 * contexts:
45 	 *  - It can be called from .probe() : No rtnl, no netdev_lock
46 	 *  - .ndo_open() : rtnl and possibly netdev_lock
47 	 *  - SFP state machine : rtnl held or not
48 	 *
49 	 *  However, we can't really have races :
50 	 *  - If we have a PHY, phy_link_topo_add_phy() will always run first
51 	 *    and trigger the alloc. Only then the ports can be added through
52 	 *    phylib or sfp.
53 	 *  - If we don't, the SFP port for the cage is registered first, and
54 	 *    only then other ports/PHYs can be registered.
55 	 */
56 	ret = netdev_alloc_phy_link_topology(dev);
57 	if (ret)
58 		return ERR_PTR(ret);
59 
60 	return dev->link_topo;
61 }
62 
63 int phy_link_topo_add_port(struct net_device *dev, struct phy_port *port)
64 {
65 	struct phy_link_topology *topo;
66 	int ret;
67 
68 	/* Ports can now be queried without rtnl for ops-locked devices, which
69 	 * we don't support now as port retrieval is done under rtnl.
70 	 * We don't have phy_port enabled devices yet, let's make sure
71 	 * we are loudly warned about that when it happens.
72 	 */
73 	if (WARN_ON_ONCE(dev->netdev_ops && netdev_need_ops_lock(dev)))
74 		return -EOPNOTSUPP;
75 
76 	topo = phy_link_topo_get_or_alloc(dev);
77 	if (IS_ERR(topo))
78 		return PTR_ERR(topo);
79 
80 	/* Attempt to re-use a previously allocated port_id */
81 	if (port->id)
82 		ret = xa_insert(&topo->ports, port->id, port, GFP_KERNEL);
83 	else
84 		ret = xa_alloc_cyclic(&topo->ports, &port->id, port,
85 				      xa_limit_32b, &topo->next_port_index,
86 				      GFP_KERNEL);
87 
88 	return ret < 0 ? ret : 0;
89 }
90 EXPORT_SYMBOL_GPL(phy_link_topo_add_port);
91 
92 void phy_link_topo_del_port(struct net_device *dev, struct phy_port *port)
93 {
94 	struct phy_link_topology *topo = dev->link_topo;
95 
96 	if (!topo)
97 		return;
98 
99 	xa_erase(&topo->ports, port->id);
100 }
101 EXPORT_SYMBOL_GPL(phy_link_topo_del_port);
102 
103 int phy_link_topo_add_phy(struct net_device *dev,
104 			  struct phy_device *phy,
105 			  enum phy_upstream upt, void *upstream)
106 {
107 	struct phy_link_topology *topo;
108 	struct phy_device_node *pdn;
109 	struct phy_port *port;
110 	int ret;
111 
112 	/* ethtool ops may run without rtnl_lock, and rtnl_lock is what
113 	 * currently protects the PHY topology. No driver currently mixes
114 	 * the two, flag if someone tries. See also:
115 	 *  - ethnl_req_get_phydev()
116 	 *  - phy_detach()
117 	 */
118 	if (WARN_ON_ONCE(netdev_need_ops_lock(dev)))
119 		return -EOPNOTSUPP;
120 
121 	topo = phy_link_topo_get_or_alloc(dev);
122 	if (IS_ERR(topo))
123 		return PTR_ERR(topo);
124 
125 	pdn = kzalloc_obj(*pdn);
126 	if (!pdn)
127 		return -ENOMEM;
128 
129 	pdn->phy = phy;
130 	switch (upt) {
131 	case PHY_UPSTREAM_MAC:
132 		pdn->upstream.netdev = (struct net_device *)upstream;
133 		if (phy_on_sfp(phy))
134 			pdn->parent_sfp_bus = pdn->upstream.netdev->sfp_bus;
135 		break;
136 	case PHY_UPSTREAM_PHY:
137 		pdn->upstream.phydev = (struct phy_device *)upstream;
138 		if (phy_on_sfp(phy))
139 			pdn->parent_sfp_bus = pdn->upstream.phydev->sfp_bus;
140 		break;
141 	default:
142 		ret = -EINVAL;
143 		goto err;
144 	}
145 	pdn->upstream_type = upt;
146 
147 	/* Attempt to re-use a previously allocated phy_index */
148 	if (phy->phyindex)
149 		ret = xa_insert(&topo->phys, phy->phyindex, pdn, GFP_KERNEL);
150 	else
151 		ret = xa_alloc_cyclic(&topo->phys, &phy->phyindex, pdn,
152 				      xa_limit_32b, &topo->next_phy_index,
153 				      GFP_KERNEL);
154 
155 	if (ret < 0)
156 		goto err;
157 
158 	/* Add all the PHY's ports to the topology */
159 	list_for_each_entry(port, &phy->ports, head) {
160 		ret = phy_link_topo_add_port(dev, port);
161 		if (ret)
162 			goto del_ports;
163 	}
164 
165 	return 0;
166 
167 del_ports:
168 	list_for_each_entry_continue_reverse(port, &phy->ports, head)
169 		phy_link_topo_del_port(dev, port);
170 
171 	xa_erase(&topo->phys, phy->phyindex);
172 err:
173 	kfree(pdn);
174 	return ret;
175 }
176 EXPORT_SYMBOL_GPL(phy_link_topo_add_phy);
177 
178 void phy_link_topo_del_phy(struct net_device *dev,
179 			   struct phy_device *phy)
180 {
181 	struct phy_link_topology *topo = dev->link_topo;
182 	struct phy_device_node *pdn;
183 	struct phy_port *port;
184 
185 	if (!topo)
186 		return;
187 
188 	list_for_each_entry(port, &phy->ports, head)
189 		phy_link_topo_del_port(dev, port);
190 
191 	pdn = xa_erase(&topo->phys, phy->phyindex);
192 
193 	/* We delete the PHY from the topology, however we don't re-set the
194 	 * phy->phyindex field. If the PHY isn't gone, we can re-assign it the
195 	 * same index next time it's added back to the topology
196 	 */
197 
198 	kfree(pdn);
199 }
200 EXPORT_SYMBOL_GPL(phy_link_topo_del_phy);
201