xref: /linux/drivers/net/phy/phy_caps.c (revision 27605c8c0f69e319df156b471974e4e223035378)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 #include <linux/ethtool.h>
4 #include <linux/linkmode.h>
5 #include <linux/phy.h>
6 
7 #include "phy-caps.h"
8 
9 static struct link_capabilities link_caps[__LINK_CAPA_MAX] __ro_after_init = {
10 	{ SPEED_10, DUPLEX_HALF, {0} }, /* LINK_CAPA_10HD */
11 	{ SPEED_10, DUPLEX_FULL, {0} }, /* LINK_CAPA_10FD */
12 	{ SPEED_100, DUPLEX_HALF, {0} }, /* LINK_CAPA_100HD */
13 	{ SPEED_100, DUPLEX_FULL, {0} }, /* LINK_CAPA_100FD */
14 	{ SPEED_1000, DUPLEX_HALF, {0} }, /* LINK_CAPA_1000HD */
15 	{ SPEED_1000, DUPLEX_FULL, {0} }, /* LINK_CAPA_1000FD */
16 	{ SPEED_2500, DUPLEX_FULL, {0} }, /* LINK_CAPA_2500FD */
17 	{ SPEED_5000, DUPLEX_FULL, {0} }, /* LINK_CAPA_5000FD */
18 	{ SPEED_10000, DUPLEX_FULL, {0} }, /* LINK_CAPA_10000FD */
19 	{ SPEED_20000, DUPLEX_FULL, {0} }, /* LINK_CAPA_20000FD */
20 	{ SPEED_25000, DUPLEX_FULL, {0} }, /* LINK_CAPA_25000FD */
21 	{ SPEED_40000, DUPLEX_FULL, {0} }, /* LINK_CAPA_40000FD */
22 	{ SPEED_50000, DUPLEX_FULL, {0} }, /* LINK_CAPA_50000FD */
23 	{ SPEED_56000, DUPLEX_FULL, {0} }, /* LINK_CAPA_56000FD */
24 	{ SPEED_100000, DUPLEX_FULL, {0} }, /* LINK_CAPA_100000FD */
25 	{ SPEED_200000, DUPLEX_FULL, {0} }, /* LINK_CAPA_200000FD */
26 	{ SPEED_400000, DUPLEX_FULL, {0} }, /* LINK_CAPA_400000FD */
27 	{ SPEED_800000, DUPLEX_FULL, {0} }, /* LINK_CAPA_800000FD */
28 };
29 
speed_duplex_to_capa(int speed,unsigned int duplex)30 static int speed_duplex_to_capa(int speed, unsigned int duplex)
31 {
32 	if (duplex == DUPLEX_UNKNOWN ||
33 	    (speed > SPEED_1000 && duplex != DUPLEX_FULL))
34 		return -EINVAL;
35 
36 	switch (speed) {
37 	case SPEED_10: return duplex == DUPLEX_FULL ?
38 			      LINK_CAPA_10FD : LINK_CAPA_10HD;
39 	case SPEED_100: return duplex == DUPLEX_FULL ?
40 			       LINK_CAPA_100FD : LINK_CAPA_100HD;
41 	case SPEED_1000: return duplex == DUPLEX_FULL ?
42 				LINK_CAPA_1000FD : LINK_CAPA_1000HD;
43 	case SPEED_2500: return LINK_CAPA_2500FD;
44 	case SPEED_5000: return LINK_CAPA_5000FD;
45 	case SPEED_10000: return LINK_CAPA_10000FD;
46 	case SPEED_20000: return LINK_CAPA_20000FD;
47 	case SPEED_25000: return LINK_CAPA_25000FD;
48 	case SPEED_40000: return LINK_CAPA_40000FD;
49 	case SPEED_50000: return LINK_CAPA_50000FD;
50 	case SPEED_56000: return LINK_CAPA_56000FD;
51 	case SPEED_100000: return LINK_CAPA_100000FD;
52 	case SPEED_200000: return LINK_CAPA_200000FD;
53 	case SPEED_400000: return LINK_CAPA_400000FD;
54 	case SPEED_800000: return LINK_CAPA_800000FD;
55 	}
56 
57 	return -EINVAL;
58 }
59 
60 #define for_each_link_caps_asc_speed(cap) \
61 	for (cap = link_caps; cap < &link_caps[__LINK_CAPA_MAX]; cap++)
62 
63 #define for_each_link_caps_desc_speed(cap) \
64 	for (cap = &link_caps[__LINK_CAPA_MAX - 1]; cap >= link_caps; cap--)
65 
66 /**
67  * phy_caps_init() - Initializes the link_caps array from the link_mode_params.
68  *
69  * Returns: 0 if phy caps init was successful, -EINVAL if we found an
70  *	    unexpected linkmode setting that requires LINK_CAPS update.
71  *
72  */
phy_caps_init(void)73 int phy_caps_init(void)
74 {
75 	const struct link_mode_info *linkmode;
76 	int i, capa;
77 
78 	/* Fill the caps array from net/ethtool/common.c */
79 	for (i = 0; i < __ETHTOOL_LINK_MODE_MASK_NBITS; i++) {
80 		linkmode = &link_mode_params[i];
81 		capa = speed_duplex_to_capa(linkmode->speed, linkmode->duplex);
82 
83 		if (capa < 0) {
84 			if (linkmode->speed != SPEED_UNKNOWN) {
85 				pr_err("Unknown speed %d, please update LINK_CAPS\n",
86 				       linkmode->speed);
87 				return -EINVAL;
88 			}
89 			continue;
90 		}
91 
92 		__set_bit(i, link_caps[capa].linkmodes);
93 	}
94 
95 	return 0;
96 }
97 
98 /**
99  * phy_caps_speeds() - Fill an array of supported SPEED_* values for given modes
100  * @speeds: Output array to store the speeds list into
101  * @size: Size of the output array
102  * @linkmodes: Linkmodes to get the speeds from
103  *
104  * Fills the speeds array with all possible speeds that can be achieved with
105  * the specified linkmodes.
106  *
107  * Returns: The number of speeds filled into the array. If the input array isn't
108  *	    big enough to store all speeds, fill it as much as possible.
109  */
phy_caps_speeds(unsigned int * speeds,size_t size,unsigned long * linkmodes)110 size_t phy_caps_speeds(unsigned int *speeds, size_t size,
111 		       unsigned long *linkmodes)
112 {
113 	struct link_capabilities *lcap;
114 	size_t count = 0;
115 
116 	for_each_link_caps_asc_speed(lcap) {
117 		if (linkmode_intersects(lcap->linkmodes, linkmodes) &&
118 		    (count == 0 || speeds[count - 1] != lcap->speed)) {
119 			speeds[count++] = lcap->speed;
120 			if (count >= size)
121 				break;
122 		}
123 	}
124 
125 	return count;
126 }
127 
128 /**
129  * phy_caps_lookup_by_linkmode() - Lookup the fastest matching link_capabilities
130  * @linkmodes: Linkmodes to match against
131  *
132  * Returns: The highest-speed link_capabilities that intersects the given
133  *	    linkmodes. In case several DUPLEX_ options exist at that speed,
134  *	    DUPLEX_FULL is matched first. NULL is returned if no match.
135  */
136 const struct link_capabilities *
phy_caps_lookup_by_linkmode(const unsigned long * linkmodes)137 phy_caps_lookup_by_linkmode(const unsigned long *linkmodes)
138 {
139 	struct link_capabilities *lcap;
140 
141 	for_each_link_caps_desc_speed(lcap)
142 		if (linkmode_intersects(lcap->linkmodes, linkmodes))
143 			return lcap;
144 
145 	return NULL;
146 }
147 
148 /**
149  * phy_caps_lookup_by_linkmode_rev() - Lookup the slowest matching link_capabilities
150  * @linkmodes: Linkmodes to match against
151  * @fdx_only: Full duplex match only when set
152  *
153  * Returns: The lowest-speed link_capabilities that intersects the given
154  *	    linkmodes. When set, fdx_only will ignore half-duplex matches.
155  *	    NULL is returned if no match.
156  */
157 const struct link_capabilities *
phy_caps_lookup_by_linkmode_rev(const unsigned long * linkmodes,bool fdx_only)158 phy_caps_lookup_by_linkmode_rev(const unsigned long *linkmodes, bool fdx_only)
159 {
160 	struct link_capabilities *lcap;
161 
162 	for_each_link_caps_asc_speed(lcap) {
163 		if (fdx_only && lcap->duplex != DUPLEX_FULL)
164 			continue;
165 
166 		if (linkmode_intersects(lcap->linkmodes, linkmodes))
167 			return lcap;
168 	}
169 
170 	return NULL;
171 }
172 
173 /**
174  * phy_caps_lookup() - Lookup capabilities by speed/duplex that matches a mask
175  * @speed: Speed to match
176  * @duplex: Duplex to match
177  * @supported: Mask of linkmodes to match
178  * @exact: Perform an exact match or not.
179  *
180  * Lookup a link_capabilities entry that intersect the supported linkmodes mask,
181  * and that matches the passed speed and duplex.
182  *
183  * When @exact is set, an exact match is performed on speed and duplex, meaning
184  * that if the linkmodes for the given speed and duplex intersect the supported
185  * mask, this capability is returned, otherwise we don't have a match and return
186  * NULL.
187  *
188  * When @exact is not set, we return either an exact match, or matching capabilities
189  * at lower speed, or the lowest matching speed, or NULL.
190  *
191  * Non-exact matches will try to return an exact speed and duplex match, but may
192  * return matching capabilities with same speed but a different duplex.
193  *
194  * Returns: a matched link_capabilities according to the above process, NULL
195  *	    otherwise.
196  */
197 const struct link_capabilities *
phy_caps_lookup(int speed,unsigned int duplex,const unsigned long * supported,bool exact)198 phy_caps_lookup(int speed, unsigned int duplex, const unsigned long *supported,
199 		bool exact)
200 {
201 	const struct link_capabilities *lcap, *match = NULL, *last = NULL;
202 
203 	for_each_link_caps_desc_speed(lcap) {
204 		if (linkmode_intersects(lcap->linkmodes, supported)) {
205 			last = lcap;
206 			/* exact match on speed and duplex*/
207 			if (lcap->speed == speed && lcap->duplex == duplex) {
208 				return lcap;
209 			} else if (!exact) {
210 				if (!match && lcap->speed <= speed)
211 					match = lcap;
212 
213 				if (lcap->speed < speed)
214 					break;
215 			}
216 		}
217 	}
218 
219 	if (!match && !exact)
220 		match = last;
221 
222 	return match;
223 }
224 EXPORT_SYMBOL_GPL(phy_caps_lookup);
225 
226 /**
227  * phy_caps_linkmode_max_speed() - Clamp a linkmodes set to a max speed
228  * @max_speed: Speed limit for the linkmode set
229  * @linkmodes: Linkmodes to limit
230  */
phy_caps_linkmode_max_speed(u32 max_speed,unsigned long * linkmodes)231 void phy_caps_linkmode_max_speed(u32 max_speed, unsigned long *linkmodes)
232 {
233 	struct link_capabilities *lcap;
234 
235 	for_each_link_caps_desc_speed(lcap)
236 		if (lcap->speed > max_speed)
237 			linkmode_andnot(linkmodes, linkmodes, lcap->linkmodes);
238 		else
239 			break;
240 }
241 
242 /**
243  * phy_caps_valid() - Validate a linkmodes set agains given speed and duplex
244  * @speed: input speed to validate
245  * @duplex: input duplex to validate. Passing DUPLEX_UNKNOWN is always not valid
246  * @linkmodes: The linkmodes to validate
247  *
248  * Returns: True if at least one of the linkmodes in @linkmodes can function at
249  *          the given speed and duplex, false otherwise.
250  */
phy_caps_valid(int speed,int duplex,const unsigned long * linkmodes)251 bool phy_caps_valid(int speed, int duplex, const unsigned long *linkmodes)
252 {
253 	int capa = speed_duplex_to_capa(speed, duplex);
254 
255 	if (capa < 0)
256 		return false;
257 
258 	return linkmode_intersects(link_caps[capa].linkmodes, linkmodes);
259 }
260 
261 /**
262  * phy_caps_linkmodes() - Convert a bitfield of capabilities into linkmodes
263  * @caps: The list of caps, each bit corresponding to a LINK_CAPA value
264  * @linkmodes: The set of linkmodes to fill. Must be previously initialized.
265  */
phy_caps_linkmodes(unsigned long caps,unsigned long * linkmodes)266 void phy_caps_linkmodes(unsigned long caps, unsigned long *linkmodes)
267 {
268 	unsigned long capa;
269 
270 	for_each_set_bit(capa, &caps, __LINK_CAPA_MAX)
271 		linkmode_or(linkmodes, linkmodes, link_caps[capa].linkmodes);
272 }
273 EXPORT_SYMBOL_GPL(phy_caps_linkmodes);
274 
275 /**
276  * phy_caps_from_interface() - Get the link capa from a given PHY interface
277  * @interface: The PHY interface we want to get the possible Speed/Duplex from
278  *
279  * Returns: A bitmask of LINK_CAPA_xxx values that can be achieved with the
280  *          provided interface.
281  */
phy_caps_from_interface(phy_interface_t interface)282 unsigned long phy_caps_from_interface(phy_interface_t interface)
283 {
284 	unsigned long link_caps = 0;
285 
286 	switch (interface) {
287 	case PHY_INTERFACE_MODE_USXGMII:
288 		link_caps |= BIT(LINK_CAPA_10000FD) | BIT(LINK_CAPA_5000FD);
289 		fallthrough;
290 
291 	case PHY_INTERFACE_MODE_10G_QXGMII:
292 		link_caps |= BIT(LINK_CAPA_2500FD);
293 		fallthrough;
294 
295 	case PHY_INTERFACE_MODE_RGMII_TXID:
296 	case PHY_INTERFACE_MODE_RGMII_RXID:
297 	case PHY_INTERFACE_MODE_RGMII_ID:
298 	case PHY_INTERFACE_MODE_RGMII:
299 	case PHY_INTERFACE_MODE_PSGMII:
300 	case PHY_INTERFACE_MODE_QSGMII:
301 	case PHY_INTERFACE_MODE_QUSGMII:
302 	case PHY_INTERFACE_MODE_SGMII:
303 	case PHY_INTERFACE_MODE_GMII:
304 		link_caps |= BIT(LINK_CAPA_1000HD) | BIT(LINK_CAPA_1000FD);
305 		fallthrough;
306 
307 	case PHY_INTERFACE_MODE_REVRMII:
308 	case PHY_INTERFACE_MODE_RMII:
309 	case PHY_INTERFACE_MODE_SMII:
310 	case PHY_INTERFACE_MODE_REVMII:
311 	case PHY_INTERFACE_MODE_MII:
312 		link_caps |= BIT(LINK_CAPA_10HD) | BIT(LINK_CAPA_10FD);
313 		fallthrough;
314 
315 	case PHY_INTERFACE_MODE_100BASEX:
316 		link_caps |= BIT(LINK_CAPA_100HD) | BIT(LINK_CAPA_100FD);
317 		break;
318 
319 	case PHY_INTERFACE_MODE_TBI:
320 	case PHY_INTERFACE_MODE_MOCA:
321 	case PHY_INTERFACE_MODE_RTBI:
322 	case PHY_INTERFACE_MODE_1000BASEX:
323 		link_caps |= BIT(LINK_CAPA_1000HD);
324 		fallthrough;
325 	case PHY_INTERFACE_MODE_1000BASEKX:
326 	case PHY_INTERFACE_MODE_TRGMII:
327 		link_caps |= BIT(LINK_CAPA_1000FD);
328 		break;
329 
330 	case PHY_INTERFACE_MODE_2500BASEX:
331 		link_caps |= BIT(LINK_CAPA_2500FD);
332 		break;
333 
334 	case PHY_INTERFACE_MODE_5GBASER:
335 		link_caps |= BIT(LINK_CAPA_5000FD);
336 		break;
337 
338 	case PHY_INTERFACE_MODE_XGMII:
339 	case PHY_INTERFACE_MODE_RXAUI:
340 	case PHY_INTERFACE_MODE_XAUI:
341 	case PHY_INTERFACE_MODE_10GBASER:
342 	case PHY_INTERFACE_MODE_10GKR:
343 		link_caps |= BIT(LINK_CAPA_10000FD);
344 		break;
345 
346 	case PHY_INTERFACE_MODE_25GBASER:
347 		link_caps |= BIT(LINK_CAPA_25000FD);
348 		break;
349 
350 	case PHY_INTERFACE_MODE_XLGMII:
351 		link_caps |= BIT(LINK_CAPA_40000FD);
352 		break;
353 
354 	case PHY_INTERFACE_MODE_INTERNAL:
355 		link_caps |= LINK_CAPA_ALL;
356 		break;
357 
358 	case PHY_INTERFACE_MODE_NA:
359 	case PHY_INTERFACE_MODE_MAX:
360 		break;
361 	}
362 
363 	return link_caps;
364 }
365 EXPORT_SYMBOL_GPL(phy_caps_from_interface);
366