1d8c838a5SMaxime Chevallier // SPDX-License-Identifier: GPL-2.0-or-later
2d8c838a5SMaxime Chevallier
3d8c838a5SMaxime Chevallier #include <linux/ethtool.h>
4d8c838a5SMaxime Chevallier #include <linux/linkmode.h>
5d8c838a5SMaxime Chevallier #include <linux/phy.h>
6d8c838a5SMaxime Chevallier
7d8c838a5SMaxime Chevallier #include "phy-caps.h"
8d8c838a5SMaxime Chevallier
9d8c838a5SMaxime Chevallier static struct link_capabilities link_caps[__LINK_CAPA_MAX] __ro_after_init = {
10d8c838a5SMaxime Chevallier { SPEED_10, DUPLEX_HALF, {0} }, /* LINK_CAPA_10HD */
11d8c838a5SMaxime Chevallier { SPEED_10, DUPLEX_FULL, {0} }, /* LINK_CAPA_10FD */
12d8c838a5SMaxime Chevallier { SPEED_100, DUPLEX_HALF, {0} }, /* LINK_CAPA_100HD */
13d8c838a5SMaxime Chevallier { SPEED_100, DUPLEX_FULL, {0} }, /* LINK_CAPA_100FD */
14d8c838a5SMaxime Chevallier { SPEED_1000, DUPLEX_HALF, {0} }, /* LINK_CAPA_1000HD */
15d8c838a5SMaxime Chevallier { SPEED_1000, DUPLEX_FULL, {0} }, /* LINK_CAPA_1000FD */
16d8c838a5SMaxime Chevallier { SPEED_2500, DUPLEX_FULL, {0} }, /* LINK_CAPA_2500FD */
17d8c838a5SMaxime Chevallier { SPEED_5000, DUPLEX_FULL, {0} }, /* LINK_CAPA_5000FD */
18d8c838a5SMaxime Chevallier { SPEED_10000, DUPLEX_FULL, {0} }, /* LINK_CAPA_10000FD */
19d8c838a5SMaxime Chevallier { SPEED_20000, DUPLEX_FULL, {0} }, /* LINK_CAPA_20000FD */
20d8c838a5SMaxime Chevallier { SPEED_25000, DUPLEX_FULL, {0} }, /* LINK_CAPA_25000FD */
21d8c838a5SMaxime Chevallier { SPEED_40000, DUPLEX_FULL, {0} }, /* LINK_CAPA_40000FD */
22d8c838a5SMaxime Chevallier { SPEED_50000, DUPLEX_FULL, {0} }, /* LINK_CAPA_50000FD */
23d8c838a5SMaxime Chevallier { SPEED_56000, DUPLEX_FULL, {0} }, /* LINK_CAPA_56000FD */
24d8c838a5SMaxime Chevallier { SPEED_100000, DUPLEX_FULL, {0} }, /* LINK_CAPA_100000FD */
25d8c838a5SMaxime Chevallier { SPEED_200000, DUPLEX_FULL, {0} }, /* LINK_CAPA_200000FD */
26d8c838a5SMaxime Chevallier { SPEED_400000, DUPLEX_FULL, {0} }, /* LINK_CAPA_400000FD */
27d8c838a5SMaxime Chevallier { SPEED_800000, DUPLEX_FULL, {0} }, /* LINK_CAPA_800000FD */
28d8c838a5SMaxime Chevallier };
29d8c838a5SMaxime Chevallier
speed_duplex_to_capa(int speed,unsigned int duplex)30d8c838a5SMaxime Chevallier static int speed_duplex_to_capa(int speed, unsigned int duplex)
31d8c838a5SMaxime Chevallier {
32d8c838a5SMaxime Chevallier if (duplex == DUPLEX_UNKNOWN ||
33d8c838a5SMaxime Chevallier (speed > SPEED_1000 && duplex != DUPLEX_FULL))
34d8c838a5SMaxime Chevallier return -EINVAL;
35d8c838a5SMaxime Chevallier
36d8c838a5SMaxime Chevallier switch (speed) {
37d8c838a5SMaxime Chevallier case SPEED_10: return duplex == DUPLEX_FULL ?
38d8c838a5SMaxime Chevallier LINK_CAPA_10FD : LINK_CAPA_10HD;
39d8c838a5SMaxime Chevallier case SPEED_100: return duplex == DUPLEX_FULL ?
40d8c838a5SMaxime Chevallier LINK_CAPA_100FD : LINK_CAPA_100HD;
41d8c838a5SMaxime Chevallier case SPEED_1000: return duplex == DUPLEX_FULL ?
42d8c838a5SMaxime Chevallier LINK_CAPA_1000FD : LINK_CAPA_1000HD;
43d8c838a5SMaxime Chevallier case SPEED_2500: return LINK_CAPA_2500FD;
44d8c838a5SMaxime Chevallier case SPEED_5000: return LINK_CAPA_5000FD;
45d8c838a5SMaxime Chevallier case SPEED_10000: return LINK_CAPA_10000FD;
46d8c838a5SMaxime Chevallier case SPEED_20000: return LINK_CAPA_20000FD;
47d8c838a5SMaxime Chevallier case SPEED_25000: return LINK_CAPA_25000FD;
48d8c838a5SMaxime Chevallier case SPEED_40000: return LINK_CAPA_40000FD;
49d8c838a5SMaxime Chevallier case SPEED_50000: return LINK_CAPA_50000FD;
50d8c838a5SMaxime Chevallier case SPEED_56000: return LINK_CAPA_56000FD;
51d8c838a5SMaxime Chevallier case SPEED_100000: return LINK_CAPA_100000FD;
52d8c838a5SMaxime Chevallier case SPEED_200000: return LINK_CAPA_200000FD;
53d8c838a5SMaxime Chevallier case SPEED_400000: return LINK_CAPA_400000FD;
54d8c838a5SMaxime Chevallier case SPEED_800000: return LINK_CAPA_800000FD;
55d8c838a5SMaxime Chevallier }
56d8c838a5SMaxime Chevallier
57d8c838a5SMaxime Chevallier return -EINVAL;
58d8c838a5SMaxime Chevallier }
59d8c838a5SMaxime Chevallier
608c8c4a87SMaxime Chevallier #define for_each_link_caps_asc_speed(cap) \
618c8c4a87SMaxime Chevallier for (cap = link_caps; cap < &link_caps[__LINK_CAPA_MAX]; cap++)
628c8c4a87SMaxime Chevallier
634823ed06SMaxime Chevallier #define for_each_link_caps_desc_speed(cap) \
644823ed06SMaxime Chevallier for (cap = &link_caps[__LINK_CAPA_MAX - 1]; cap >= link_caps; cap--)
654823ed06SMaxime Chevallier
66d8c838a5SMaxime Chevallier /**
67d8c838a5SMaxime Chevallier * phy_caps_init() - Initializes the link_caps array from the link_mode_params.
68d8c838a5SMaxime Chevallier *
69d8c838a5SMaxime Chevallier * Returns: 0 if phy caps init was successful, -EINVAL if we found an
70d8c838a5SMaxime Chevallier * unexpected linkmode setting that requires LINK_CAPS update.
71d8c838a5SMaxime Chevallier *
72d8c838a5SMaxime Chevallier */
phy_caps_init(void)73d8c838a5SMaxime Chevallier int phy_caps_init(void)
74d8c838a5SMaxime Chevallier {
75d8c838a5SMaxime Chevallier const struct link_mode_info *linkmode;
76d8c838a5SMaxime Chevallier int i, capa;
77d8c838a5SMaxime Chevallier
78d8c838a5SMaxime Chevallier /* Fill the caps array from net/ethtool/common.c */
79d8c838a5SMaxime Chevallier for (i = 0; i < __ETHTOOL_LINK_MODE_MASK_NBITS; i++) {
80d8c838a5SMaxime Chevallier linkmode = &link_mode_params[i];
81d8c838a5SMaxime Chevallier capa = speed_duplex_to_capa(linkmode->speed, linkmode->duplex);
82d8c838a5SMaxime Chevallier
83d8c838a5SMaxime Chevallier if (capa < 0) {
84d8c838a5SMaxime Chevallier if (linkmode->speed != SPEED_UNKNOWN) {
85d8c838a5SMaxime Chevallier pr_err("Unknown speed %d, please update LINK_CAPS\n",
86d8c838a5SMaxime Chevallier linkmode->speed);
87d8c838a5SMaxime Chevallier return -EINVAL;
88d8c838a5SMaxime Chevallier }
89d8c838a5SMaxime Chevallier continue;
90d8c838a5SMaxime Chevallier }
91d8c838a5SMaxime Chevallier
92d8c838a5SMaxime Chevallier __set_bit(i, link_caps[capa].linkmodes);
93d8c838a5SMaxime Chevallier }
94d8c838a5SMaxime Chevallier
95d8c838a5SMaxime Chevallier return 0;
96d8c838a5SMaxime Chevallier }
978c8c4a87SMaxime Chevallier
988c8c4a87SMaxime Chevallier /**
998c8c4a87SMaxime Chevallier * phy_caps_speeds() - Fill an array of supported SPEED_* values for given modes
1008c8c4a87SMaxime Chevallier * @speeds: Output array to store the speeds list into
1018c8c4a87SMaxime Chevallier * @size: Size of the output array
1028c8c4a87SMaxime Chevallier * @linkmodes: Linkmodes to get the speeds from
1038c8c4a87SMaxime Chevallier *
1048c8c4a87SMaxime Chevallier * Fills the speeds array with all possible speeds that can be achieved with
1058c8c4a87SMaxime Chevallier * the specified linkmodes.
1068c8c4a87SMaxime Chevallier *
1078c8c4a87SMaxime Chevallier * Returns: The number of speeds filled into the array. If the input array isn't
1088c8c4a87SMaxime Chevallier * big enough to store all speeds, fill it as much as possible.
1098c8c4a87SMaxime Chevallier */
phy_caps_speeds(unsigned int * speeds,size_t size,unsigned long * linkmodes)1108c8c4a87SMaxime Chevallier size_t phy_caps_speeds(unsigned int *speeds, size_t size,
1118c8c4a87SMaxime Chevallier unsigned long *linkmodes)
1128c8c4a87SMaxime Chevallier {
1138c8c4a87SMaxime Chevallier struct link_capabilities *lcap;
1148c8c4a87SMaxime Chevallier size_t count = 0;
1158c8c4a87SMaxime Chevallier
1168c8c4a87SMaxime Chevallier for_each_link_caps_asc_speed(lcap) {
1178c8c4a87SMaxime Chevallier if (linkmode_intersects(lcap->linkmodes, linkmodes) &&
1188c8c4a87SMaxime Chevallier (count == 0 || speeds[count - 1] != lcap->speed)) {
1198c8c4a87SMaxime Chevallier speeds[count++] = lcap->speed;
1208c8c4a87SMaxime Chevallier if (count >= size)
1218c8c4a87SMaxime Chevallier break;
1228c8c4a87SMaxime Chevallier }
1238c8c4a87SMaxime Chevallier }
1248c8c4a87SMaxime Chevallier
1258c8c4a87SMaxime Chevallier return count;
1268c8c4a87SMaxime Chevallier }
1274823ed06SMaxime Chevallier
1284823ed06SMaxime Chevallier /**
129dbcd85b0SMaxime Chevallier * phy_caps_lookup_by_linkmode() - Lookup the fastest matching link_capabilities
130dbcd85b0SMaxime Chevallier * @linkmodes: Linkmodes to match against
131dbcd85b0SMaxime Chevallier *
132dbcd85b0SMaxime Chevallier * Returns: The highest-speed link_capabilities that intersects the given
133dbcd85b0SMaxime Chevallier * linkmodes. In case several DUPLEX_ options exist at that speed,
134dbcd85b0SMaxime Chevallier * DUPLEX_FULL is matched first. NULL is returned if no match.
135dbcd85b0SMaxime Chevallier */
136dbcd85b0SMaxime Chevallier const struct link_capabilities *
phy_caps_lookup_by_linkmode(const unsigned long * linkmodes)137dbcd85b0SMaxime Chevallier phy_caps_lookup_by_linkmode(const unsigned long *linkmodes)
138dbcd85b0SMaxime Chevallier {
139dbcd85b0SMaxime Chevallier struct link_capabilities *lcap;
140dbcd85b0SMaxime Chevallier
141dbcd85b0SMaxime Chevallier for_each_link_caps_desc_speed(lcap)
142dbcd85b0SMaxime Chevallier if (linkmode_intersects(lcap->linkmodes, linkmodes))
143dbcd85b0SMaxime Chevallier return lcap;
144dbcd85b0SMaxime Chevallier
145dbcd85b0SMaxime Chevallier return NULL;
146dbcd85b0SMaxime Chevallier }
147dbcd85b0SMaxime Chevallier
148dbcd85b0SMaxime Chevallier /**
149dbcd85b0SMaxime Chevallier * phy_caps_lookup_by_linkmode_rev() - Lookup the slowest matching link_capabilities
150dbcd85b0SMaxime Chevallier * @linkmodes: Linkmodes to match against
151dbcd85b0SMaxime Chevallier * @fdx_only: Full duplex match only when set
152dbcd85b0SMaxime Chevallier *
153dbcd85b0SMaxime Chevallier * Returns: The lowest-speed link_capabilities that intersects the given
154dbcd85b0SMaxime Chevallier * linkmodes. When set, fdx_only will ignore half-duplex matches.
155dbcd85b0SMaxime Chevallier * NULL is returned if no match.
156dbcd85b0SMaxime Chevallier */
157dbcd85b0SMaxime Chevallier const struct link_capabilities *
phy_caps_lookup_by_linkmode_rev(const unsigned long * linkmodes,bool fdx_only)158dbcd85b0SMaxime Chevallier phy_caps_lookup_by_linkmode_rev(const unsigned long *linkmodes, bool fdx_only)
159dbcd85b0SMaxime Chevallier {
160dbcd85b0SMaxime Chevallier struct link_capabilities *lcap;
161dbcd85b0SMaxime Chevallier
162dbcd85b0SMaxime Chevallier for_each_link_caps_asc_speed(lcap) {
163dbcd85b0SMaxime Chevallier if (fdx_only && lcap->duplex != DUPLEX_FULL)
164dbcd85b0SMaxime Chevallier continue;
165dbcd85b0SMaxime Chevallier
166dbcd85b0SMaxime Chevallier if (linkmode_intersects(lcap->linkmodes, linkmodes))
167dbcd85b0SMaxime Chevallier return lcap;
168dbcd85b0SMaxime Chevallier }
169dbcd85b0SMaxime Chevallier
170dbcd85b0SMaxime Chevallier return NULL;
171dbcd85b0SMaxime Chevallier }
172dbcd85b0SMaxime Chevallier
173dbcd85b0SMaxime Chevallier /**
174fc81e257SMaxime Chevallier * phy_caps_lookup() - Lookup capabilities by speed/duplex that matches a mask
175fc81e257SMaxime Chevallier * @speed: Speed to match
176fc81e257SMaxime Chevallier * @duplex: Duplex to match
177fc81e257SMaxime Chevallier * @supported: Mask of linkmodes to match
178fc81e257SMaxime Chevallier * @exact: Perform an exact match or not.
179fc81e257SMaxime Chevallier *
180fc81e257SMaxime Chevallier * Lookup a link_capabilities entry that intersect the supported linkmodes mask,
181fc81e257SMaxime Chevallier * and that matches the passed speed and duplex.
182fc81e257SMaxime Chevallier *
183fc81e257SMaxime Chevallier * When @exact is set, an exact match is performed on speed and duplex, meaning
184fc81e257SMaxime Chevallier * that if the linkmodes for the given speed and duplex intersect the supported
185fc81e257SMaxime Chevallier * mask, this capability is returned, otherwise we don't have a match and return
186fc81e257SMaxime Chevallier * NULL.
187fc81e257SMaxime Chevallier *
188fc81e257SMaxime Chevallier * When @exact is not set, we return either an exact match, or matching capabilities
189fc81e257SMaxime Chevallier * at lower speed, or the lowest matching speed, or NULL.
190fc81e257SMaxime Chevallier *
191fc81e257SMaxime Chevallier * Returns: a matched link_capabilities according to the above process, NULL
192fc81e257SMaxime Chevallier * otherwise.
193fc81e257SMaxime Chevallier */
194fc81e257SMaxime Chevallier const struct link_capabilities *
phy_caps_lookup(int speed,unsigned int duplex,const unsigned long * supported,bool exact)195fc81e257SMaxime Chevallier phy_caps_lookup(int speed, unsigned int duplex, const unsigned long *supported,
196fc81e257SMaxime Chevallier bool exact)
197fc81e257SMaxime Chevallier {
198fc81e257SMaxime Chevallier const struct link_capabilities *lcap, *last = NULL;
199fc81e257SMaxime Chevallier
200fc81e257SMaxime Chevallier for_each_link_caps_desc_speed(lcap) {
201fc81e257SMaxime Chevallier if (linkmode_intersects(lcap->linkmodes, supported)) {
202fc81e257SMaxime Chevallier last = lcap;
203fc81e257SMaxime Chevallier /* exact match on speed and duplex*/
204fc81e257SMaxime Chevallier if (lcap->speed == speed && lcap->duplex == duplex) {
205fc81e257SMaxime Chevallier return lcap;
206fc81e257SMaxime Chevallier } else if (!exact) {
207fc81e257SMaxime Chevallier if (lcap->speed <= speed)
208fc81e257SMaxime Chevallier return lcap;
209fc81e257SMaxime Chevallier }
210fc81e257SMaxime Chevallier }
211fc81e257SMaxime Chevallier }
212fc81e257SMaxime Chevallier
213fc81e257SMaxime Chevallier if (!exact)
214fc81e257SMaxime Chevallier return last;
215fc81e257SMaxime Chevallier
216fc81e257SMaxime Chevallier return NULL;
217fc81e257SMaxime Chevallier }
218fc81e257SMaxime Chevallier EXPORT_SYMBOL_GPL(phy_caps_lookup);
219fc81e257SMaxime Chevallier
220fc81e257SMaxime Chevallier /**
2214823ed06SMaxime Chevallier * phy_caps_linkmode_max_speed() - Clamp a linkmodes set to a max speed
2224823ed06SMaxime Chevallier * @max_speed: Speed limit for the linkmode set
2234823ed06SMaxime Chevallier * @linkmodes: Linkmodes to limit
2244823ed06SMaxime Chevallier */
phy_caps_linkmode_max_speed(u32 max_speed,unsigned long * linkmodes)2254823ed06SMaxime Chevallier void phy_caps_linkmode_max_speed(u32 max_speed, unsigned long *linkmodes)
2264823ed06SMaxime Chevallier {
2274823ed06SMaxime Chevallier struct link_capabilities *lcap;
2284823ed06SMaxime Chevallier
2294823ed06SMaxime Chevallier for_each_link_caps_desc_speed(lcap)
2304823ed06SMaxime Chevallier if (lcap->speed > max_speed)
2314823ed06SMaxime Chevallier linkmode_andnot(linkmodes, linkmodes, lcap->linkmodes);
2324823ed06SMaxime Chevallier else
2334823ed06SMaxime Chevallier break;
2344823ed06SMaxime Chevallier }
23587b22ce3SMaxime Chevallier
23687b22ce3SMaxime Chevallier /**
23787b22ce3SMaxime Chevallier * phy_caps_valid() - Validate a linkmodes set agains given speed and duplex
23887b22ce3SMaxime Chevallier * @speed: input speed to validate
23987b22ce3SMaxime Chevallier * @duplex: input duplex to validate. Passing DUPLEX_UNKNOWN is always not valid
24087b22ce3SMaxime Chevallier * @linkmodes: The linkmodes to validate
24187b22ce3SMaxime Chevallier *
24287b22ce3SMaxime Chevallier * Returns: True if at least one of the linkmodes in @linkmodes can function at
24387b22ce3SMaxime Chevallier * the given speed and duplex, false otherwise.
24487b22ce3SMaxime Chevallier */
phy_caps_valid(int speed,int duplex,const unsigned long * linkmodes)24587b22ce3SMaxime Chevallier bool phy_caps_valid(int speed, int duplex, const unsigned long *linkmodes)
24687b22ce3SMaxime Chevallier {
24787b22ce3SMaxime Chevallier int capa = speed_duplex_to_capa(speed, duplex);
24887b22ce3SMaxime Chevallier
24987b22ce3SMaxime Chevallier if (capa < 0)
25087b22ce3SMaxime Chevallier return false;
25187b22ce3SMaxime Chevallier
25287b22ce3SMaxime Chevallier return linkmode_intersects(link_caps[capa].linkmodes, linkmodes);
25387b22ce3SMaxime Chevallier }
2544ca5b8a2SMaxime Chevallier
2554ca5b8a2SMaxime Chevallier /**
2564ca5b8a2SMaxime Chevallier * phy_caps_linkmodes() - Convert a bitfield of capabilities into linkmodes
2574ca5b8a2SMaxime Chevallier * @caps: The list of caps, each bit corresponding to a LINK_CAPA value
2584ca5b8a2SMaxime Chevallier * @linkmodes: The set of linkmodes to fill. Must be previously initialized.
2594ca5b8a2SMaxime Chevallier */
phy_caps_linkmodes(unsigned long caps,unsigned long * linkmodes)2604ca5b8a2SMaxime Chevallier void phy_caps_linkmodes(unsigned long caps, unsigned long *linkmodes)
2614ca5b8a2SMaxime Chevallier {
2624ca5b8a2SMaxime Chevallier unsigned long capa;
2634ca5b8a2SMaxime Chevallier
2644ca5b8a2SMaxime Chevallier for_each_set_bit(capa, &caps, __LINK_CAPA_MAX)
2654ca5b8a2SMaxime Chevallier linkmode_or(linkmodes, linkmodes, link_caps[capa].linkmodes);
2664ca5b8a2SMaxime Chevallier }
2674ca5b8a2SMaxime Chevallier EXPORT_SYMBOL_GPL(phy_caps_linkmodes);
268*3bd87f3bSMaxime Chevallier
269*3bd87f3bSMaxime Chevallier /**
270*3bd87f3bSMaxime Chevallier * phy_caps_from_interface() - Get the link capa from a given PHY interface
271*3bd87f3bSMaxime Chevallier * @interface: The PHY interface we want to get the possible Speed/Duplex from
272*3bd87f3bSMaxime Chevallier *
273*3bd87f3bSMaxime Chevallier * Returns: A bitmask of LINK_CAPA_xxx values that can be achieved with the
274*3bd87f3bSMaxime Chevallier * provided interface.
275*3bd87f3bSMaxime Chevallier */
phy_caps_from_interface(phy_interface_t interface)276*3bd87f3bSMaxime Chevallier unsigned long phy_caps_from_interface(phy_interface_t interface)
277*3bd87f3bSMaxime Chevallier {
278*3bd87f3bSMaxime Chevallier unsigned long link_caps = 0;
279*3bd87f3bSMaxime Chevallier
280*3bd87f3bSMaxime Chevallier switch (interface) {
281*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_USXGMII:
282*3bd87f3bSMaxime Chevallier link_caps |= BIT(LINK_CAPA_10000FD) | BIT(LINK_CAPA_5000FD);
283*3bd87f3bSMaxime Chevallier fallthrough;
284*3bd87f3bSMaxime Chevallier
285*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_10G_QXGMII:
286*3bd87f3bSMaxime Chevallier link_caps |= BIT(LINK_CAPA_2500FD);
287*3bd87f3bSMaxime Chevallier fallthrough;
288*3bd87f3bSMaxime Chevallier
289*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_RGMII_TXID:
290*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_RGMII_RXID:
291*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_RGMII_ID:
292*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_RGMII:
293*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_PSGMII:
294*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_QSGMII:
295*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_QUSGMII:
296*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_SGMII:
297*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_GMII:
298*3bd87f3bSMaxime Chevallier link_caps |= BIT(LINK_CAPA_1000HD) | BIT(LINK_CAPA_1000FD);
299*3bd87f3bSMaxime Chevallier fallthrough;
300*3bd87f3bSMaxime Chevallier
301*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_REVRMII:
302*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_RMII:
303*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_SMII:
304*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_REVMII:
305*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_MII:
306*3bd87f3bSMaxime Chevallier link_caps |= BIT(LINK_CAPA_10HD) | BIT(LINK_CAPA_10FD);
307*3bd87f3bSMaxime Chevallier fallthrough;
308*3bd87f3bSMaxime Chevallier
309*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_100BASEX:
310*3bd87f3bSMaxime Chevallier link_caps |= BIT(LINK_CAPA_100HD) | BIT(LINK_CAPA_100FD);
311*3bd87f3bSMaxime Chevallier break;
312*3bd87f3bSMaxime Chevallier
313*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_TBI:
314*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_MOCA:
315*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_RTBI:
316*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_1000BASEX:
317*3bd87f3bSMaxime Chevallier link_caps |= BIT(LINK_CAPA_1000HD);
318*3bd87f3bSMaxime Chevallier fallthrough;
319*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_1000BASEKX:
320*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_TRGMII:
321*3bd87f3bSMaxime Chevallier link_caps |= BIT(LINK_CAPA_1000FD);
322*3bd87f3bSMaxime Chevallier break;
323*3bd87f3bSMaxime Chevallier
324*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_2500BASEX:
325*3bd87f3bSMaxime Chevallier link_caps |= BIT(LINK_CAPA_2500FD);
326*3bd87f3bSMaxime Chevallier break;
327*3bd87f3bSMaxime Chevallier
328*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_5GBASER:
329*3bd87f3bSMaxime Chevallier link_caps |= BIT(LINK_CAPA_5000FD);
330*3bd87f3bSMaxime Chevallier break;
331*3bd87f3bSMaxime Chevallier
332*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_XGMII:
333*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_RXAUI:
334*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_XAUI:
335*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_10GBASER:
336*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_10GKR:
337*3bd87f3bSMaxime Chevallier link_caps |= BIT(LINK_CAPA_10000FD);
338*3bd87f3bSMaxime Chevallier break;
339*3bd87f3bSMaxime Chevallier
340*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_25GBASER:
341*3bd87f3bSMaxime Chevallier link_caps |= BIT(LINK_CAPA_25000FD);
342*3bd87f3bSMaxime Chevallier break;
343*3bd87f3bSMaxime Chevallier
344*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_XLGMII:
345*3bd87f3bSMaxime Chevallier link_caps |= BIT(LINK_CAPA_40000FD);
346*3bd87f3bSMaxime Chevallier break;
347*3bd87f3bSMaxime Chevallier
348*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_INTERNAL:
349*3bd87f3bSMaxime Chevallier link_caps |= LINK_CAPA_ALL;
350*3bd87f3bSMaxime Chevallier break;
351*3bd87f3bSMaxime Chevallier
352*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_NA:
353*3bd87f3bSMaxime Chevallier case PHY_INTERFACE_MODE_MAX:
354*3bd87f3bSMaxime Chevallier break;
355*3bd87f3bSMaxime Chevallier }
356*3bd87f3bSMaxime Chevallier
357*3bd87f3bSMaxime Chevallier return link_caps;
358*3bd87f3bSMaxime Chevallier }
359*3bd87f3bSMaxime Chevallier EXPORT_SYMBOL_GPL(phy_caps_from_interface);
360