File Index
Files and directories
Sign in
FILE

phy_caps.c

File preview with syntax highlighting.

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