1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Core PHY library, taken from phy.c |
4 | */ |
5 | #include <linux/export.h> |
6 | #include <linux/phy.h> |
7 | #include <linux/of.h> |
8 | |
9 | /** |
10 | * phy_speed_to_str - Return a string representing the PHY link speed |
11 | * |
12 | * @speed: Speed of the link |
13 | */ |
14 | const char *phy_speed_to_str(int speed) |
15 | { |
16 | BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 102, |
17 | "Enum ethtool_link_mode_bit_indices and phylib are out of sync. " |
18 | "If a speed or mode has been added please update phy_speed_to_str " |
19 | "and the PHY settings array.\n" ); |
20 | |
21 | switch (speed) { |
22 | case SPEED_10: |
23 | return "10Mbps" ; |
24 | case SPEED_100: |
25 | return "100Mbps" ; |
26 | case SPEED_1000: |
27 | return "1Gbps" ; |
28 | case SPEED_2500: |
29 | return "2.5Gbps" ; |
30 | case SPEED_5000: |
31 | return "5Gbps" ; |
32 | case SPEED_10000: |
33 | return "10Gbps" ; |
34 | case SPEED_14000: |
35 | return "14Gbps" ; |
36 | case SPEED_20000: |
37 | return "20Gbps" ; |
38 | case SPEED_25000: |
39 | return "25Gbps" ; |
40 | case SPEED_40000: |
41 | return "40Gbps" ; |
42 | case SPEED_50000: |
43 | return "50Gbps" ; |
44 | case SPEED_56000: |
45 | return "56Gbps" ; |
46 | case SPEED_100000: |
47 | return "100Gbps" ; |
48 | case SPEED_200000: |
49 | return "200Gbps" ; |
50 | case SPEED_400000: |
51 | return "400Gbps" ; |
52 | case SPEED_800000: |
53 | return "800Gbps" ; |
54 | case SPEED_UNKNOWN: |
55 | return "Unknown" ; |
56 | default: |
57 | return "Unsupported (update phy-core.c)" ; |
58 | } |
59 | } |
60 | EXPORT_SYMBOL_GPL(phy_speed_to_str); |
61 | |
62 | /** |
63 | * phy_duplex_to_str - Return string describing the duplex |
64 | * |
65 | * @duplex: Duplex setting to describe |
66 | */ |
67 | const char *phy_duplex_to_str(unsigned int duplex) |
68 | { |
69 | if (duplex == DUPLEX_HALF) |
70 | return "Half" ; |
71 | if (duplex == DUPLEX_FULL) |
72 | return "Full" ; |
73 | if (duplex == DUPLEX_UNKNOWN) |
74 | return "Unknown" ; |
75 | return "Unsupported (update phy-core.c)" ; |
76 | } |
77 | EXPORT_SYMBOL_GPL(phy_duplex_to_str); |
78 | |
79 | /** |
80 | * phy_rate_matching_to_str - Return a string describing the rate matching |
81 | * |
82 | * @rate_matching: Type of rate matching to describe |
83 | */ |
84 | const char *phy_rate_matching_to_str(int rate_matching) |
85 | { |
86 | switch (rate_matching) { |
87 | case RATE_MATCH_NONE: |
88 | return "none" ; |
89 | case RATE_MATCH_PAUSE: |
90 | return "pause" ; |
91 | case RATE_MATCH_CRS: |
92 | return "crs" ; |
93 | case RATE_MATCH_OPEN_LOOP: |
94 | return "open-loop" ; |
95 | } |
96 | return "Unsupported (update phy-core.c)" ; |
97 | } |
98 | EXPORT_SYMBOL_GPL(phy_rate_matching_to_str); |
99 | |
100 | /** |
101 | * phy_interface_num_ports - Return the number of links that can be carried by |
102 | * a given MAC-PHY physical link. Returns 0 if this is |
103 | * unknown, the number of links else. |
104 | * |
105 | * @interface: The interface mode we want to get the number of ports |
106 | */ |
107 | int phy_interface_num_ports(phy_interface_t interface) |
108 | { |
109 | switch (interface) { |
110 | case PHY_INTERFACE_MODE_NA: |
111 | return 0; |
112 | case PHY_INTERFACE_MODE_INTERNAL: |
113 | case PHY_INTERFACE_MODE_MII: |
114 | case PHY_INTERFACE_MODE_GMII: |
115 | case PHY_INTERFACE_MODE_TBI: |
116 | case PHY_INTERFACE_MODE_REVMII: |
117 | case PHY_INTERFACE_MODE_RMII: |
118 | case PHY_INTERFACE_MODE_REVRMII: |
119 | case PHY_INTERFACE_MODE_RGMII: |
120 | case PHY_INTERFACE_MODE_RGMII_ID: |
121 | case PHY_INTERFACE_MODE_RGMII_RXID: |
122 | case PHY_INTERFACE_MODE_RGMII_TXID: |
123 | case PHY_INTERFACE_MODE_RTBI: |
124 | case PHY_INTERFACE_MODE_XGMII: |
125 | case PHY_INTERFACE_MODE_XLGMII: |
126 | case PHY_INTERFACE_MODE_MOCA: |
127 | case PHY_INTERFACE_MODE_TRGMII: |
128 | case PHY_INTERFACE_MODE_USXGMII: |
129 | case PHY_INTERFACE_MODE_SGMII: |
130 | case PHY_INTERFACE_MODE_SMII: |
131 | case PHY_INTERFACE_MODE_1000BASEX: |
132 | case PHY_INTERFACE_MODE_2500BASEX: |
133 | case PHY_INTERFACE_MODE_5GBASER: |
134 | case PHY_INTERFACE_MODE_10GBASER: |
135 | case PHY_INTERFACE_MODE_25GBASER: |
136 | case PHY_INTERFACE_MODE_10GKR: |
137 | case PHY_INTERFACE_MODE_100BASEX: |
138 | case PHY_INTERFACE_MODE_RXAUI: |
139 | case PHY_INTERFACE_MODE_XAUI: |
140 | case PHY_INTERFACE_MODE_1000BASEKX: |
141 | return 1; |
142 | case PHY_INTERFACE_MODE_QSGMII: |
143 | case PHY_INTERFACE_MODE_QUSGMII: |
144 | return 4; |
145 | case PHY_INTERFACE_MODE_PSGMII: |
146 | return 5; |
147 | case PHY_INTERFACE_MODE_MAX: |
148 | WARN_ONCE(1, "PHY_INTERFACE_MODE_MAX isn't a valid interface mode" ); |
149 | return 0; |
150 | } |
151 | return 0; |
152 | } |
153 | EXPORT_SYMBOL_GPL(phy_interface_num_ports); |
154 | |
155 | /* A mapping of all SUPPORTED settings to speed/duplex. This table |
156 | * must be grouped by speed and sorted in descending match priority |
157 | * - iow, descending speed. |
158 | */ |
159 | |
160 | #define PHY_SETTING(s, d, b) { .speed = SPEED_ ## s, .duplex = DUPLEX_ ## d, \ |
161 | .bit = ETHTOOL_LINK_MODE_ ## b ## _BIT} |
162 | |
163 | static const struct phy_setting settings[] = { |
164 | /* 800G */ |
165 | PHY_SETTING( 800000, FULL, 800000baseCR8_Full ), |
166 | PHY_SETTING( 800000, FULL, 800000baseKR8_Full ), |
167 | PHY_SETTING( 800000, FULL, 800000baseDR8_Full ), |
168 | PHY_SETTING( 800000, FULL, 800000baseDR8_2_Full ), |
169 | PHY_SETTING( 800000, FULL, 800000baseSR8_Full ), |
170 | PHY_SETTING( 800000, FULL, 800000baseVR8_Full ), |
171 | /* 400G */ |
172 | PHY_SETTING( 400000, FULL, 400000baseCR8_Full ), |
173 | PHY_SETTING( 400000, FULL, 400000baseKR8_Full ), |
174 | PHY_SETTING( 400000, FULL, 400000baseLR8_ER8_FR8_Full ), |
175 | PHY_SETTING( 400000, FULL, 400000baseDR8_Full ), |
176 | PHY_SETTING( 400000, FULL, 400000baseSR8_Full ), |
177 | PHY_SETTING( 400000, FULL, 400000baseCR4_Full ), |
178 | PHY_SETTING( 400000, FULL, 400000baseKR4_Full ), |
179 | PHY_SETTING( 400000, FULL, 400000baseLR4_ER4_FR4_Full ), |
180 | PHY_SETTING( 400000, FULL, 400000baseDR4_Full ), |
181 | PHY_SETTING( 400000, FULL, 400000baseSR4_Full ), |
182 | /* 200G */ |
183 | PHY_SETTING( 200000, FULL, 200000baseCR4_Full ), |
184 | PHY_SETTING( 200000, FULL, 200000baseKR4_Full ), |
185 | PHY_SETTING( 200000, FULL, 200000baseLR4_ER4_FR4_Full ), |
186 | PHY_SETTING( 200000, FULL, 200000baseDR4_Full ), |
187 | PHY_SETTING( 200000, FULL, 200000baseSR4_Full ), |
188 | PHY_SETTING( 200000, FULL, 200000baseCR2_Full ), |
189 | PHY_SETTING( 200000, FULL, 200000baseKR2_Full ), |
190 | PHY_SETTING( 200000, FULL, 200000baseLR2_ER2_FR2_Full ), |
191 | PHY_SETTING( 200000, FULL, 200000baseDR2_Full ), |
192 | PHY_SETTING( 200000, FULL, 200000baseSR2_Full ), |
193 | /* 100G */ |
194 | PHY_SETTING( 100000, FULL, 100000baseCR4_Full ), |
195 | PHY_SETTING( 100000, FULL, 100000baseKR4_Full ), |
196 | PHY_SETTING( 100000, FULL, 100000baseLR4_ER4_Full ), |
197 | PHY_SETTING( 100000, FULL, 100000baseSR4_Full ), |
198 | PHY_SETTING( 100000, FULL, 100000baseCR2_Full ), |
199 | PHY_SETTING( 100000, FULL, 100000baseKR2_Full ), |
200 | PHY_SETTING( 100000, FULL, 100000baseLR2_ER2_FR2_Full ), |
201 | PHY_SETTING( 100000, FULL, 100000baseDR2_Full ), |
202 | PHY_SETTING( 100000, FULL, 100000baseSR2_Full ), |
203 | PHY_SETTING( 100000, FULL, 100000baseCR_Full ), |
204 | PHY_SETTING( 100000, FULL, 100000baseKR_Full ), |
205 | PHY_SETTING( 100000, FULL, 100000baseLR_ER_FR_Full ), |
206 | PHY_SETTING( 100000, FULL, 100000baseDR_Full ), |
207 | PHY_SETTING( 100000, FULL, 100000baseSR_Full ), |
208 | /* 56G */ |
209 | PHY_SETTING( 56000, FULL, 56000baseCR4_Full ), |
210 | PHY_SETTING( 56000, FULL, 56000baseKR4_Full ), |
211 | PHY_SETTING( 56000, FULL, 56000baseLR4_Full ), |
212 | PHY_SETTING( 56000, FULL, 56000baseSR4_Full ), |
213 | /* 50G */ |
214 | PHY_SETTING( 50000, FULL, 50000baseCR2_Full ), |
215 | PHY_SETTING( 50000, FULL, 50000baseKR2_Full ), |
216 | PHY_SETTING( 50000, FULL, 50000baseSR2_Full ), |
217 | PHY_SETTING( 50000, FULL, 50000baseCR_Full ), |
218 | PHY_SETTING( 50000, FULL, 50000baseKR_Full ), |
219 | PHY_SETTING( 50000, FULL, 50000baseLR_ER_FR_Full ), |
220 | PHY_SETTING( 50000, FULL, 50000baseDR_Full ), |
221 | PHY_SETTING( 50000, FULL, 50000baseSR_Full ), |
222 | /* 40G */ |
223 | PHY_SETTING( 40000, FULL, 40000baseCR4_Full ), |
224 | PHY_SETTING( 40000, FULL, 40000baseKR4_Full ), |
225 | PHY_SETTING( 40000, FULL, 40000baseLR4_Full ), |
226 | PHY_SETTING( 40000, FULL, 40000baseSR4_Full ), |
227 | /* 25G */ |
228 | PHY_SETTING( 25000, FULL, 25000baseCR_Full ), |
229 | PHY_SETTING( 25000, FULL, 25000baseKR_Full ), |
230 | PHY_SETTING( 25000, FULL, 25000baseSR_Full ), |
231 | /* 20G */ |
232 | PHY_SETTING( 20000, FULL, 20000baseKR2_Full ), |
233 | PHY_SETTING( 20000, FULL, 20000baseMLD2_Full ), |
234 | /* 10G */ |
235 | PHY_SETTING( 10000, FULL, 10000baseCR_Full ), |
236 | PHY_SETTING( 10000, FULL, 10000baseER_Full ), |
237 | PHY_SETTING( 10000, FULL, 10000baseKR_Full ), |
238 | PHY_SETTING( 10000, FULL, 10000baseKX4_Full ), |
239 | PHY_SETTING( 10000, FULL, 10000baseLR_Full ), |
240 | PHY_SETTING( 10000, FULL, 10000baseLRM_Full ), |
241 | PHY_SETTING( 10000, FULL, 10000baseR_FEC ), |
242 | PHY_SETTING( 10000, FULL, 10000baseSR_Full ), |
243 | PHY_SETTING( 10000, FULL, 10000baseT_Full ), |
244 | /* 5G */ |
245 | PHY_SETTING( 5000, FULL, 5000baseT_Full ), |
246 | /* 2.5G */ |
247 | PHY_SETTING( 2500, FULL, 2500baseT_Full ), |
248 | PHY_SETTING( 2500, FULL, 2500baseX_Full ), |
249 | /* 1G */ |
250 | PHY_SETTING( 1000, FULL, 1000baseT_Full ), |
251 | PHY_SETTING( 1000, HALF, 1000baseT_Half ), |
252 | PHY_SETTING( 1000, FULL, 1000baseT1_Full ), |
253 | PHY_SETTING( 1000, FULL, 1000baseX_Full ), |
254 | PHY_SETTING( 1000, FULL, 1000baseKX_Full ), |
255 | /* 100M */ |
256 | PHY_SETTING( 100, FULL, 100baseT_Full ), |
257 | PHY_SETTING( 100, FULL, 100baseT1_Full ), |
258 | PHY_SETTING( 100, HALF, 100baseT_Half ), |
259 | PHY_SETTING( 100, HALF, 100baseFX_Half ), |
260 | PHY_SETTING( 100, FULL, 100baseFX_Full ), |
261 | /* 10M */ |
262 | PHY_SETTING( 10, FULL, 10baseT_Full ), |
263 | PHY_SETTING( 10, HALF, 10baseT_Half ), |
264 | PHY_SETTING( 10, FULL, 10baseT1L_Full ), |
265 | PHY_SETTING( 10, FULL, 10baseT1S_Full ), |
266 | PHY_SETTING( 10, HALF, 10baseT1S_Half ), |
267 | PHY_SETTING( 10, HALF, 10baseT1S_P2MP_Half ), |
268 | }; |
269 | #undef PHY_SETTING |
270 | |
271 | /** |
272 | * phy_lookup_setting - lookup a PHY setting |
273 | * @speed: speed to match |
274 | * @duplex: duplex to match |
275 | * @mask: allowed link modes |
276 | * @exact: an exact match is required |
277 | * |
278 | * Search the settings array for a setting that matches the speed and |
279 | * duplex, and which is supported. |
280 | * |
281 | * If @exact is unset, either an exact match or %NULL for no match will |
282 | * be returned. |
283 | * |
284 | * If @exact is set, an exact match, the fastest supported setting at |
285 | * or below the specified speed, the slowest supported setting, or if |
286 | * they all fail, %NULL will be returned. |
287 | */ |
288 | const struct phy_setting * |
289 | phy_lookup_setting(int speed, int duplex, const unsigned long *mask, bool exact) |
290 | { |
291 | const struct phy_setting *p, *match = NULL, *last = NULL; |
292 | int i; |
293 | |
294 | for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) { |
295 | if (p->bit < __ETHTOOL_LINK_MODE_MASK_NBITS && |
296 | test_bit(p->bit, mask)) { |
297 | last = p; |
298 | if (p->speed == speed && p->duplex == duplex) { |
299 | /* Exact match for speed and duplex */ |
300 | match = p; |
301 | break; |
302 | } else if (!exact) { |
303 | if (!match && p->speed <= speed) |
304 | /* Candidate */ |
305 | match = p; |
306 | |
307 | if (p->speed < speed) |
308 | break; |
309 | } |
310 | } |
311 | } |
312 | |
313 | if (!match && !exact) |
314 | match = last; |
315 | |
316 | return match; |
317 | } |
318 | EXPORT_SYMBOL_GPL(phy_lookup_setting); |
319 | |
320 | size_t phy_speeds(unsigned int *speeds, size_t size, |
321 | unsigned long *mask) |
322 | { |
323 | size_t count; |
324 | int i; |
325 | |
326 | for (i = 0, count = 0; i < ARRAY_SIZE(settings) && count < size; i++) |
327 | if (settings[i].bit < __ETHTOOL_LINK_MODE_MASK_NBITS && |
328 | test_bit(settings[i].bit, mask) && |
329 | (count == 0 || speeds[count - 1] != settings[i].speed)) |
330 | speeds[count++] = settings[i].speed; |
331 | |
332 | return count; |
333 | } |
334 | |
335 | static void __set_linkmode_max_speed(u32 max_speed, unsigned long *addr) |
336 | { |
337 | const struct phy_setting *p; |
338 | int i; |
339 | |
340 | for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) { |
341 | if (p->speed > max_speed) |
342 | linkmode_clear_bit(nr: p->bit, addr); |
343 | else |
344 | break; |
345 | } |
346 | } |
347 | |
348 | static void __set_phy_supported(struct phy_device *phydev, u32 max_speed) |
349 | { |
350 | __set_linkmode_max_speed(max_speed, addr: phydev->supported); |
351 | } |
352 | |
353 | /** |
354 | * phy_set_max_speed - Set the maximum speed the PHY should support |
355 | * |
356 | * @phydev: The phy_device struct |
357 | * @max_speed: Maximum speed |
358 | * |
359 | * The PHY might be more capable than the MAC. For example a Fast Ethernet |
360 | * is connected to a 1G PHY. This function allows the MAC to indicate its |
361 | * maximum speed, and so limit what the PHY will advertise. |
362 | */ |
363 | void phy_set_max_speed(struct phy_device *phydev, u32 max_speed) |
364 | { |
365 | __set_phy_supported(phydev, max_speed); |
366 | |
367 | phy_advertise_supported(phydev); |
368 | } |
369 | EXPORT_SYMBOL(phy_set_max_speed); |
370 | |
371 | void of_set_phy_supported(struct phy_device *phydev) |
372 | { |
373 | struct device_node *node = phydev->mdio.dev.of_node; |
374 | u32 max_speed; |
375 | |
376 | if (!IS_ENABLED(CONFIG_OF_MDIO)) |
377 | return; |
378 | |
379 | if (!node) |
380 | return; |
381 | |
382 | if (!of_property_read_u32(np: node, propname: "max-speed" , out_value: &max_speed)) |
383 | __set_phy_supported(phydev, max_speed); |
384 | } |
385 | |
386 | void of_set_phy_eee_broken(struct phy_device *phydev) |
387 | { |
388 | struct device_node *node = phydev->mdio.dev.of_node; |
389 | u32 broken = 0; |
390 | |
391 | if (!IS_ENABLED(CONFIG_OF_MDIO)) |
392 | return; |
393 | |
394 | if (!node) |
395 | return; |
396 | |
397 | if (of_property_read_bool(np: node, propname: "eee-broken-100tx" )) |
398 | broken |= MDIO_EEE_100TX; |
399 | if (of_property_read_bool(np: node, propname: "eee-broken-1000t" )) |
400 | broken |= MDIO_EEE_1000T; |
401 | if (of_property_read_bool(np: node, propname: "eee-broken-10gt" )) |
402 | broken |= MDIO_EEE_10GT; |
403 | if (of_property_read_bool(np: node, propname: "eee-broken-1000kx" )) |
404 | broken |= MDIO_EEE_1000KX; |
405 | if (of_property_read_bool(np: node, propname: "eee-broken-10gkx4" )) |
406 | broken |= MDIO_EEE_10GKX4; |
407 | if (of_property_read_bool(np: node, propname: "eee-broken-10gkr" )) |
408 | broken |= MDIO_EEE_10GKR; |
409 | |
410 | phydev->eee_broken_modes = broken; |
411 | } |
412 | |
413 | /** |
414 | * phy_resolve_aneg_pause - Determine pause autoneg results |
415 | * |
416 | * @phydev: The phy_device struct |
417 | * |
418 | * Once autoneg has completed the local pause settings can be |
419 | * resolved. Determine if pause and asymmetric pause should be used |
420 | * by the MAC. |
421 | */ |
422 | |
423 | void phy_resolve_aneg_pause(struct phy_device *phydev) |
424 | { |
425 | if (phydev->duplex == DUPLEX_FULL) { |
426 | phydev->pause = linkmode_test_bit(nr: ETHTOOL_LINK_MODE_Pause_BIT, |
427 | addr: phydev->lp_advertising); |
428 | phydev->asym_pause = linkmode_test_bit( |
429 | nr: ETHTOOL_LINK_MODE_Asym_Pause_BIT, |
430 | addr: phydev->lp_advertising); |
431 | } |
432 | } |
433 | EXPORT_SYMBOL_GPL(phy_resolve_aneg_pause); |
434 | |
435 | /** |
436 | * phy_resolve_aneg_linkmode - resolve the advertisements into PHY settings |
437 | * @phydev: The phy_device struct |
438 | * |
439 | * Resolve our and the link partner advertisements into their corresponding |
440 | * speed and duplex. If full duplex was negotiated, extract the pause mode |
441 | * from the link partner mask. |
442 | */ |
443 | void phy_resolve_aneg_linkmode(struct phy_device *phydev) |
444 | { |
445 | __ETHTOOL_DECLARE_LINK_MODE_MASK(common); |
446 | int i; |
447 | |
448 | linkmode_and(dst: common, a: phydev->lp_advertising, b: phydev->advertising); |
449 | |
450 | for (i = 0; i < ARRAY_SIZE(settings); i++) |
451 | if (test_bit(settings[i].bit, common)) { |
452 | phydev->speed = settings[i].speed; |
453 | phydev->duplex = settings[i].duplex; |
454 | break; |
455 | } |
456 | |
457 | phy_resolve_aneg_pause(phydev); |
458 | } |
459 | EXPORT_SYMBOL_GPL(phy_resolve_aneg_linkmode); |
460 | |
461 | /** |
462 | * phy_check_downshift - check whether downshift occurred |
463 | * @phydev: The phy_device struct |
464 | * |
465 | * Check whether a downshift to a lower speed occurred. If this should be the |
466 | * case warn the user. |
467 | * Prerequisite for detecting downshift is that PHY driver implements the |
468 | * read_status callback and sets phydev->speed to the actual link speed. |
469 | */ |
470 | void phy_check_downshift(struct phy_device *phydev) |
471 | { |
472 | __ETHTOOL_DECLARE_LINK_MODE_MASK(common); |
473 | int i, speed = SPEED_UNKNOWN; |
474 | |
475 | phydev->downshifted_rate = 0; |
476 | |
477 | if (phydev->autoneg == AUTONEG_DISABLE || |
478 | phydev->speed == SPEED_UNKNOWN) |
479 | return; |
480 | |
481 | linkmode_and(dst: common, a: phydev->lp_advertising, b: phydev->advertising); |
482 | |
483 | for (i = 0; i < ARRAY_SIZE(settings); i++) |
484 | if (test_bit(settings[i].bit, common)) { |
485 | speed = settings[i].speed; |
486 | break; |
487 | } |
488 | |
489 | if (speed == SPEED_UNKNOWN || phydev->speed >= speed) |
490 | return; |
491 | |
492 | phydev_warn(phydev, "Downshift occurred from negotiated speed %s to actual speed %s, check cabling!\n" , |
493 | phy_speed_to_str(speed), phy_speed_to_str(phydev->speed)); |
494 | |
495 | phydev->downshifted_rate = 1; |
496 | } |
497 | EXPORT_SYMBOL_GPL(phy_check_downshift); |
498 | |
499 | static int phy_resolve_min_speed(struct phy_device *phydev, bool fdx_only) |
500 | { |
501 | __ETHTOOL_DECLARE_LINK_MODE_MASK(common); |
502 | int i = ARRAY_SIZE(settings); |
503 | |
504 | linkmode_and(dst: common, a: phydev->lp_advertising, b: phydev->advertising); |
505 | |
506 | while (--i >= 0) { |
507 | if (test_bit(settings[i].bit, common)) { |
508 | if (fdx_only && settings[i].duplex != DUPLEX_FULL) |
509 | continue; |
510 | return settings[i].speed; |
511 | } |
512 | } |
513 | |
514 | return SPEED_UNKNOWN; |
515 | } |
516 | |
517 | int phy_speed_down_core(struct phy_device *phydev) |
518 | { |
519 | int min_common_speed = phy_resolve_min_speed(phydev, fdx_only: true); |
520 | |
521 | if (min_common_speed == SPEED_UNKNOWN) |
522 | return -EINVAL; |
523 | |
524 | __set_linkmode_max_speed(max_speed: min_common_speed, addr: phydev->advertising); |
525 | |
526 | return 0; |
527 | } |
528 | |
529 | static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad, |
530 | u16 regnum) |
531 | { |
532 | /* Write the desired MMD Devad */ |
533 | __mdiobus_write(bus, addr: phy_addr, MII_MMD_CTRL, val: devad); |
534 | |
535 | /* Write the desired MMD register address */ |
536 | __mdiobus_write(bus, addr: phy_addr, MII_MMD_DATA, val: regnum); |
537 | |
538 | /* Select the Function : DATA with no post increment */ |
539 | __mdiobus_write(bus, addr: phy_addr, MII_MMD_CTRL, |
540 | val: devad | MII_MMD_CTRL_NOINCR); |
541 | } |
542 | |
543 | static int mmd_phy_read(struct mii_bus *bus, int phy_addr, bool is_c45, |
544 | int devad, u32 regnum) |
545 | { |
546 | if (is_c45) |
547 | return __mdiobus_c45_read(bus, addr: phy_addr, devad, regnum); |
548 | |
549 | mmd_phy_indirect(bus, phy_addr, devad, regnum); |
550 | /* Read the content of the MMD's selected register */ |
551 | return __mdiobus_read(bus, addr: phy_addr, MII_MMD_DATA); |
552 | } |
553 | |
554 | static int mmd_phy_write(struct mii_bus *bus, int phy_addr, bool is_c45, |
555 | int devad, u32 regnum, u16 val) |
556 | { |
557 | if (is_c45) |
558 | return __mdiobus_c45_write(bus, addr: phy_addr, devad, regnum, val); |
559 | |
560 | mmd_phy_indirect(bus, phy_addr, devad, regnum); |
561 | /* Write the data into MMD's selected register */ |
562 | return __mdiobus_write(bus, addr: phy_addr, MII_MMD_DATA, val); |
563 | } |
564 | |
565 | /** |
566 | * __phy_read_mmd - Convenience function for reading a register |
567 | * from an MMD on a given PHY. |
568 | * @phydev: The phy_device struct |
569 | * @devad: The MMD to read from (0..31) |
570 | * @regnum: The register on the MMD to read (0..65535) |
571 | * |
572 | * Same rules as for __phy_read(); |
573 | */ |
574 | int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum) |
575 | { |
576 | if (regnum > (u16)~0 || devad > 32) |
577 | return -EINVAL; |
578 | |
579 | if (phydev->drv && phydev->drv->read_mmd) |
580 | return phydev->drv->read_mmd(phydev, devad, regnum); |
581 | |
582 | return mmd_phy_read(bus: phydev->mdio.bus, phy_addr: phydev->mdio.addr, |
583 | is_c45: phydev->is_c45, devad, regnum); |
584 | } |
585 | EXPORT_SYMBOL(__phy_read_mmd); |
586 | |
587 | /** |
588 | * phy_read_mmd - Convenience function for reading a register |
589 | * from an MMD on a given PHY. |
590 | * @phydev: The phy_device struct |
591 | * @devad: The MMD to read from |
592 | * @regnum: The register on the MMD to read |
593 | * |
594 | * Same rules as for phy_read(); |
595 | */ |
596 | int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum) |
597 | { |
598 | int ret; |
599 | |
600 | phy_lock_mdio_bus(phydev); |
601 | ret = __phy_read_mmd(phydev, devad, regnum); |
602 | phy_unlock_mdio_bus(phydev); |
603 | |
604 | return ret; |
605 | } |
606 | EXPORT_SYMBOL(phy_read_mmd); |
607 | |
608 | /** |
609 | * __phy_write_mmd - Convenience function for writing a register |
610 | * on an MMD on a given PHY. |
611 | * @phydev: The phy_device struct |
612 | * @devad: The MMD to read from |
613 | * @regnum: The register on the MMD to read |
614 | * @val: value to write to @regnum |
615 | * |
616 | * Same rules as for __phy_write(); |
617 | */ |
618 | int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val) |
619 | { |
620 | if (regnum > (u16)~0 || devad > 32) |
621 | return -EINVAL; |
622 | |
623 | if (phydev->drv && phydev->drv->write_mmd) |
624 | return phydev->drv->write_mmd(phydev, devad, regnum, val); |
625 | |
626 | return mmd_phy_write(bus: phydev->mdio.bus, phy_addr: phydev->mdio.addr, |
627 | is_c45: phydev->is_c45, devad, regnum, val); |
628 | } |
629 | EXPORT_SYMBOL(__phy_write_mmd); |
630 | |
631 | /** |
632 | * phy_write_mmd - Convenience function for writing a register |
633 | * on an MMD on a given PHY. |
634 | * @phydev: The phy_device struct |
635 | * @devad: The MMD to read from |
636 | * @regnum: The register on the MMD to read |
637 | * @val: value to write to @regnum |
638 | * |
639 | * Same rules as for phy_write(); |
640 | */ |
641 | int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val) |
642 | { |
643 | int ret; |
644 | |
645 | phy_lock_mdio_bus(phydev); |
646 | ret = __phy_write_mmd(phydev, devad, regnum, val); |
647 | phy_unlock_mdio_bus(phydev); |
648 | |
649 | return ret; |
650 | } |
651 | EXPORT_SYMBOL(phy_write_mmd); |
652 | |
653 | /** |
654 | * __phy_package_read_mmd - read MMD reg relative to PHY package base addr |
655 | * @phydev: The phy_device struct |
656 | * @addr_offset: The offset to be added to PHY package base_addr |
657 | * @devad: The MMD to read from |
658 | * @regnum: The register on the MMD to read |
659 | * |
660 | * Convenience helper for reading a register of an MMD on a given PHY |
661 | * using the PHY package base address. The base address is added to |
662 | * the addr_offset value. |
663 | * |
664 | * Same calling rules as for __phy_read(); |
665 | * |
666 | * NOTE: It's assumed that the entire PHY package is either C22 or C45. |
667 | */ |
668 | int __phy_package_read_mmd(struct phy_device *phydev, |
669 | unsigned int addr_offset, int devad, |
670 | u32 regnum) |
671 | { |
672 | int addr = phy_package_address(phydev, addr_offset); |
673 | |
674 | if (addr < 0) |
675 | return addr; |
676 | |
677 | if (regnum > (u16)~0 || devad > 32) |
678 | return -EINVAL; |
679 | |
680 | return mmd_phy_read(bus: phydev->mdio.bus, phy_addr: addr, is_c45: phydev->is_c45, devad, |
681 | regnum); |
682 | } |
683 | EXPORT_SYMBOL(__phy_package_read_mmd); |
684 | |
685 | /** |
686 | * phy_package_read_mmd - read MMD reg relative to PHY package base addr |
687 | * @phydev: The phy_device struct |
688 | * @addr_offset: The offset to be added to PHY package base_addr |
689 | * @devad: The MMD to read from |
690 | * @regnum: The register on the MMD to read |
691 | * |
692 | * Convenience helper for reading a register of an MMD on a given PHY |
693 | * using the PHY package base address. The base address is added to |
694 | * the addr_offset value. |
695 | * |
696 | * Same calling rules as for phy_read(); |
697 | * |
698 | * NOTE: It's assumed that the entire PHY package is either C22 or C45. |
699 | */ |
700 | int phy_package_read_mmd(struct phy_device *phydev, |
701 | unsigned int addr_offset, int devad, |
702 | u32 regnum) |
703 | { |
704 | int addr = phy_package_address(phydev, addr_offset); |
705 | int val; |
706 | |
707 | if (addr < 0) |
708 | return addr; |
709 | |
710 | if (regnum > (u16)~0 || devad > 32) |
711 | return -EINVAL; |
712 | |
713 | phy_lock_mdio_bus(phydev); |
714 | val = mmd_phy_read(bus: phydev->mdio.bus, phy_addr: addr, is_c45: phydev->is_c45, devad, |
715 | regnum); |
716 | phy_unlock_mdio_bus(phydev); |
717 | |
718 | return val; |
719 | } |
720 | EXPORT_SYMBOL(phy_package_read_mmd); |
721 | |
722 | /** |
723 | * __phy_package_write_mmd - write MMD reg relative to PHY package base addr |
724 | * @phydev: The phy_device struct |
725 | * @addr_offset: The offset to be added to PHY package base_addr |
726 | * @devad: The MMD to write to |
727 | * @regnum: The register on the MMD to write |
728 | * @val: value to write to @regnum |
729 | * |
730 | * Convenience helper for writing a register of an MMD on a given PHY |
731 | * using the PHY package base address. The base address is added to |
732 | * the addr_offset value. |
733 | * |
734 | * Same calling rules as for __phy_write(); |
735 | * |
736 | * NOTE: It's assumed that the entire PHY package is either C22 or C45. |
737 | */ |
738 | int __phy_package_write_mmd(struct phy_device *phydev, |
739 | unsigned int addr_offset, int devad, |
740 | u32 regnum, u16 val) |
741 | { |
742 | int addr = phy_package_address(phydev, addr_offset); |
743 | |
744 | if (addr < 0) |
745 | return addr; |
746 | |
747 | if (regnum > (u16)~0 || devad > 32) |
748 | return -EINVAL; |
749 | |
750 | return mmd_phy_write(bus: phydev->mdio.bus, phy_addr: addr, is_c45: phydev->is_c45, devad, |
751 | regnum, val); |
752 | } |
753 | EXPORT_SYMBOL(__phy_package_write_mmd); |
754 | |
755 | /** |
756 | * phy_package_write_mmd - write MMD reg relative to PHY package base addr |
757 | * @phydev: The phy_device struct |
758 | * @addr_offset: The offset to be added to PHY package base_addr |
759 | * @devad: The MMD to write to |
760 | * @regnum: The register on the MMD to write |
761 | * @val: value to write to @regnum |
762 | * |
763 | * Convenience helper for writing a register of an MMD on a given PHY |
764 | * using the PHY package base address. The base address is added to |
765 | * the addr_offset value. |
766 | * |
767 | * Same calling rules as for phy_write(); |
768 | * |
769 | * NOTE: It's assumed that the entire PHY package is either C22 or C45. |
770 | */ |
771 | int phy_package_write_mmd(struct phy_device *phydev, |
772 | unsigned int addr_offset, int devad, |
773 | u32 regnum, u16 val) |
774 | { |
775 | int addr = phy_package_address(phydev, addr_offset); |
776 | int ret; |
777 | |
778 | if (addr < 0) |
779 | return addr; |
780 | |
781 | if (regnum > (u16)~0 || devad > 32) |
782 | return -EINVAL; |
783 | |
784 | phy_lock_mdio_bus(phydev); |
785 | ret = mmd_phy_write(bus: phydev->mdio.bus, phy_addr: addr, is_c45: phydev->is_c45, devad, |
786 | regnum, val); |
787 | phy_unlock_mdio_bus(phydev); |
788 | |
789 | return ret; |
790 | } |
791 | EXPORT_SYMBOL(phy_package_write_mmd); |
792 | |
793 | /** |
794 | * phy_modify_changed - Function for modifying a PHY register |
795 | * @phydev: the phy_device struct |
796 | * @regnum: register number to modify |
797 | * @mask: bit mask of bits to clear |
798 | * @set: new value of bits set in mask to write to @regnum |
799 | * |
800 | * NOTE: MUST NOT be called from interrupt context, |
801 | * because the bus read/write functions may wait for an interrupt |
802 | * to conclude the operation. |
803 | * |
804 | * Returns negative errno, 0 if there was no change, and 1 in case of change |
805 | */ |
806 | int phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask, u16 set) |
807 | { |
808 | int ret; |
809 | |
810 | phy_lock_mdio_bus(phydev); |
811 | ret = __phy_modify_changed(phydev, regnum, mask, set); |
812 | phy_unlock_mdio_bus(phydev); |
813 | |
814 | return ret; |
815 | } |
816 | EXPORT_SYMBOL_GPL(phy_modify_changed); |
817 | |
818 | /** |
819 | * __phy_modify - Convenience function for modifying a PHY register |
820 | * @phydev: the phy_device struct |
821 | * @regnum: register number to modify |
822 | * @mask: bit mask of bits to clear |
823 | * @set: new value of bits set in mask to write to @regnum |
824 | * |
825 | * NOTE: MUST NOT be called from interrupt context, |
826 | * because the bus read/write functions may wait for an interrupt |
827 | * to conclude the operation. |
828 | */ |
829 | int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set) |
830 | { |
831 | int ret; |
832 | |
833 | ret = __phy_modify_changed(phydev, regnum, mask, set); |
834 | |
835 | return ret < 0 ? ret : 0; |
836 | } |
837 | EXPORT_SYMBOL_GPL(__phy_modify); |
838 | |
839 | /** |
840 | * phy_modify - Convenience function for modifying a given PHY register |
841 | * @phydev: the phy_device struct |
842 | * @regnum: register number to write |
843 | * @mask: bit mask of bits to clear |
844 | * @set: new value of bits set in mask to write to @regnum |
845 | * |
846 | * NOTE: MUST NOT be called from interrupt context, |
847 | * because the bus read/write functions may wait for an interrupt |
848 | * to conclude the operation. |
849 | */ |
850 | int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set) |
851 | { |
852 | int ret; |
853 | |
854 | phy_lock_mdio_bus(phydev); |
855 | ret = __phy_modify(phydev, regnum, mask, set); |
856 | phy_unlock_mdio_bus(phydev); |
857 | |
858 | return ret; |
859 | } |
860 | EXPORT_SYMBOL_GPL(phy_modify); |
861 | |
862 | /** |
863 | * __phy_modify_mmd_changed - Function for modifying a register on MMD |
864 | * @phydev: the phy_device struct |
865 | * @devad: the MMD containing register to modify |
866 | * @regnum: register number to modify |
867 | * @mask: bit mask of bits to clear |
868 | * @set: new value of bits set in mask to write to @regnum |
869 | * |
870 | * Unlocked helper function which allows a MMD register to be modified as |
871 | * new register value = (old register value & ~mask) | set |
872 | * |
873 | * Returns negative errno, 0 if there was no change, and 1 in case of change |
874 | */ |
875 | int __phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum, |
876 | u16 mask, u16 set) |
877 | { |
878 | int new, ret; |
879 | |
880 | ret = __phy_read_mmd(phydev, devad, regnum); |
881 | if (ret < 0) |
882 | return ret; |
883 | |
884 | new = (ret & ~mask) | set; |
885 | if (new == ret) |
886 | return 0; |
887 | |
888 | ret = __phy_write_mmd(phydev, devad, regnum, new); |
889 | |
890 | return ret < 0 ? ret : 1; |
891 | } |
892 | EXPORT_SYMBOL_GPL(__phy_modify_mmd_changed); |
893 | |
894 | /** |
895 | * phy_modify_mmd_changed - Function for modifying a register on MMD |
896 | * @phydev: the phy_device struct |
897 | * @devad: the MMD containing register to modify |
898 | * @regnum: register number to modify |
899 | * @mask: bit mask of bits to clear |
900 | * @set: new value of bits set in mask to write to @regnum |
901 | * |
902 | * NOTE: MUST NOT be called from interrupt context, |
903 | * because the bus read/write functions may wait for an interrupt |
904 | * to conclude the operation. |
905 | * |
906 | * Returns negative errno, 0 if there was no change, and 1 in case of change |
907 | */ |
908 | int phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum, |
909 | u16 mask, u16 set) |
910 | { |
911 | int ret; |
912 | |
913 | phy_lock_mdio_bus(phydev); |
914 | ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set); |
915 | phy_unlock_mdio_bus(phydev); |
916 | |
917 | return ret; |
918 | } |
919 | EXPORT_SYMBOL_GPL(phy_modify_mmd_changed); |
920 | |
921 | /** |
922 | * __phy_modify_mmd - Convenience function for modifying a register on MMD |
923 | * @phydev: the phy_device struct |
924 | * @devad: the MMD containing register to modify |
925 | * @regnum: register number to modify |
926 | * @mask: bit mask of bits to clear |
927 | * @set: new value of bits set in mask to write to @regnum |
928 | * |
929 | * NOTE: MUST NOT be called from interrupt context, |
930 | * because the bus read/write functions may wait for an interrupt |
931 | * to conclude the operation. |
932 | */ |
933 | int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum, |
934 | u16 mask, u16 set) |
935 | { |
936 | int ret; |
937 | |
938 | ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set); |
939 | |
940 | return ret < 0 ? ret : 0; |
941 | } |
942 | EXPORT_SYMBOL_GPL(__phy_modify_mmd); |
943 | |
944 | /** |
945 | * phy_modify_mmd - Convenience function for modifying a register on MMD |
946 | * @phydev: the phy_device struct |
947 | * @devad: the MMD containing register to modify |
948 | * @regnum: register number to modify |
949 | * @mask: bit mask of bits to clear |
950 | * @set: new value of bits set in mask to write to @regnum |
951 | * |
952 | * NOTE: MUST NOT be called from interrupt context, |
953 | * because the bus read/write functions may wait for an interrupt |
954 | * to conclude the operation. |
955 | */ |
956 | int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum, |
957 | u16 mask, u16 set) |
958 | { |
959 | int ret; |
960 | |
961 | phy_lock_mdio_bus(phydev); |
962 | ret = __phy_modify_mmd(phydev, devad, regnum, mask, set); |
963 | phy_unlock_mdio_bus(phydev); |
964 | |
965 | return ret; |
966 | } |
967 | EXPORT_SYMBOL_GPL(phy_modify_mmd); |
968 | |
969 | static int __phy_read_page(struct phy_device *phydev) |
970 | { |
971 | if (WARN_ONCE(!phydev->drv->read_page, "read_page callback not available, PHY driver not loaded?\n" )) |
972 | return -EOPNOTSUPP; |
973 | |
974 | return phydev->drv->read_page(phydev); |
975 | } |
976 | |
977 | static int __phy_write_page(struct phy_device *phydev, int page) |
978 | { |
979 | if (WARN_ONCE(!phydev->drv->write_page, "write_page callback not available, PHY driver not loaded?\n" )) |
980 | return -EOPNOTSUPP; |
981 | |
982 | return phydev->drv->write_page(phydev, page); |
983 | } |
984 | |
985 | /** |
986 | * phy_save_page() - take the bus lock and save the current page |
987 | * @phydev: a pointer to a &struct phy_device |
988 | * |
989 | * Take the MDIO bus lock, and return the current page number. On error, |
990 | * returns a negative errno. phy_restore_page() must always be called |
991 | * after this, irrespective of success or failure of this call. |
992 | */ |
993 | int phy_save_page(struct phy_device *phydev) |
994 | { |
995 | phy_lock_mdio_bus(phydev); |
996 | return __phy_read_page(phydev); |
997 | } |
998 | EXPORT_SYMBOL_GPL(phy_save_page); |
999 | |
1000 | /** |
1001 | * phy_select_page() - take the bus lock, save the current page, and set a page |
1002 | * @phydev: a pointer to a &struct phy_device |
1003 | * @page: desired page |
1004 | * |
1005 | * Take the MDIO bus lock to protect against concurrent access, save the |
1006 | * current PHY page, and set the current page. On error, returns a |
1007 | * negative errno, otherwise returns the previous page number. |
1008 | * phy_restore_page() must always be called after this, irrespective |
1009 | * of success or failure of this call. |
1010 | */ |
1011 | int phy_select_page(struct phy_device *phydev, int page) |
1012 | { |
1013 | int ret, oldpage; |
1014 | |
1015 | oldpage = ret = phy_save_page(phydev); |
1016 | if (ret < 0) |
1017 | return ret; |
1018 | |
1019 | if (oldpage != page) { |
1020 | ret = __phy_write_page(phydev, page); |
1021 | if (ret < 0) |
1022 | return ret; |
1023 | } |
1024 | |
1025 | return oldpage; |
1026 | } |
1027 | EXPORT_SYMBOL_GPL(phy_select_page); |
1028 | |
1029 | /** |
1030 | * phy_restore_page() - restore the page register and release the bus lock |
1031 | * @phydev: a pointer to a &struct phy_device |
1032 | * @oldpage: the old page, return value from phy_save_page() or phy_select_page() |
1033 | * @ret: operation's return code |
1034 | * |
1035 | * Release the MDIO bus lock, restoring @oldpage if it is a valid page. |
1036 | * This function propagates the earliest error code from the group of |
1037 | * operations. |
1038 | * |
1039 | * Returns: |
1040 | * @oldpage if it was a negative value, otherwise |
1041 | * @ret if it was a negative errno value, otherwise |
1042 | * phy_write_page()'s negative value if it were in error, otherwise |
1043 | * @ret. |
1044 | */ |
1045 | int phy_restore_page(struct phy_device *phydev, int oldpage, int ret) |
1046 | { |
1047 | int r; |
1048 | |
1049 | if (oldpage >= 0) { |
1050 | r = __phy_write_page(phydev, page: oldpage); |
1051 | |
1052 | /* Propagate the operation return code if the page write |
1053 | * was successful. |
1054 | */ |
1055 | if (ret >= 0 && r < 0) |
1056 | ret = r; |
1057 | } else { |
1058 | /* Propagate the phy page selection error code */ |
1059 | ret = oldpage; |
1060 | } |
1061 | |
1062 | phy_unlock_mdio_bus(phydev); |
1063 | |
1064 | return ret; |
1065 | } |
1066 | EXPORT_SYMBOL_GPL(phy_restore_page); |
1067 | |
1068 | /** |
1069 | * phy_read_paged() - Convenience function for reading a paged register |
1070 | * @phydev: a pointer to a &struct phy_device |
1071 | * @page: the page for the phy |
1072 | * @regnum: register number |
1073 | * |
1074 | * Same rules as for phy_read(). |
1075 | */ |
1076 | int phy_read_paged(struct phy_device *phydev, int page, u32 regnum) |
1077 | { |
1078 | int ret = 0, oldpage; |
1079 | |
1080 | oldpage = phy_select_page(phydev, page); |
1081 | if (oldpage >= 0) |
1082 | ret = __phy_read(phydev, regnum); |
1083 | |
1084 | return phy_restore_page(phydev, oldpage, ret); |
1085 | } |
1086 | EXPORT_SYMBOL(phy_read_paged); |
1087 | |
1088 | /** |
1089 | * phy_write_paged() - Convenience function for writing a paged register |
1090 | * @phydev: a pointer to a &struct phy_device |
1091 | * @page: the page for the phy |
1092 | * @regnum: register number |
1093 | * @val: value to write |
1094 | * |
1095 | * Same rules as for phy_write(). |
1096 | */ |
1097 | int phy_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val) |
1098 | { |
1099 | int ret = 0, oldpage; |
1100 | |
1101 | oldpage = phy_select_page(phydev, page); |
1102 | if (oldpage >= 0) |
1103 | ret = __phy_write(phydev, regnum, val); |
1104 | |
1105 | return phy_restore_page(phydev, oldpage, ret); |
1106 | } |
1107 | EXPORT_SYMBOL(phy_write_paged); |
1108 | |
1109 | /** |
1110 | * phy_modify_paged_changed() - Function for modifying a paged register |
1111 | * @phydev: a pointer to a &struct phy_device |
1112 | * @page: the page for the phy |
1113 | * @regnum: register number |
1114 | * @mask: bit mask of bits to clear |
1115 | * @set: bit mask of bits to set |
1116 | * |
1117 | * Returns negative errno, 0 if there was no change, and 1 in case of change |
1118 | */ |
1119 | int phy_modify_paged_changed(struct phy_device *phydev, int page, u32 regnum, |
1120 | u16 mask, u16 set) |
1121 | { |
1122 | int ret = 0, oldpage; |
1123 | |
1124 | oldpage = phy_select_page(phydev, page); |
1125 | if (oldpage >= 0) |
1126 | ret = __phy_modify_changed(phydev, regnum, mask, set); |
1127 | |
1128 | return phy_restore_page(phydev, oldpage, ret); |
1129 | } |
1130 | EXPORT_SYMBOL(phy_modify_paged_changed); |
1131 | |
1132 | /** |
1133 | * phy_modify_paged() - Convenience function for modifying a paged register |
1134 | * @phydev: a pointer to a &struct phy_device |
1135 | * @page: the page for the phy |
1136 | * @regnum: register number |
1137 | * @mask: bit mask of bits to clear |
1138 | * @set: bit mask of bits to set |
1139 | * |
1140 | * Same rules as for phy_read() and phy_write(). |
1141 | */ |
1142 | int phy_modify_paged(struct phy_device *phydev, int page, u32 regnum, |
1143 | u16 mask, u16 set) |
1144 | { |
1145 | int ret = phy_modify_paged_changed(phydev, page, regnum, mask, set); |
1146 | |
1147 | return ret < 0 ? ret : 0; |
1148 | } |
1149 | EXPORT_SYMBOL(phy_modify_paged); |
1150 | |