xref: /openbmc/linux/drivers/net/phy/phy-core.c (revision a2443fd1)
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 
8 const char *phy_speed_to_str(int speed)
9 {
10 	switch (speed) {
11 	case SPEED_10:
12 		return "10Mbps";
13 	case SPEED_100:
14 		return "100Mbps";
15 	case SPEED_1000:
16 		return "1Gbps";
17 	case SPEED_2500:
18 		return "2.5Gbps";
19 	case SPEED_5000:
20 		return "5Gbps";
21 	case SPEED_10000:
22 		return "10Gbps";
23 	case SPEED_14000:
24 		return "14Gbps";
25 	case SPEED_20000:
26 		return "20Gbps";
27 	case SPEED_25000:
28 		return "25Gbps";
29 	case SPEED_40000:
30 		return "40Gbps";
31 	case SPEED_50000:
32 		return "50Gbps";
33 	case SPEED_56000:
34 		return "56Gbps";
35 	case SPEED_100000:
36 		return "100Gbps";
37 	case SPEED_UNKNOWN:
38 		return "Unknown";
39 	default:
40 		return "Unsupported (update phy-core.c)";
41 	}
42 }
43 EXPORT_SYMBOL_GPL(phy_speed_to_str);
44 
45 const char *phy_duplex_to_str(unsigned int duplex)
46 {
47 	if (duplex == DUPLEX_HALF)
48 		return "Half";
49 	if (duplex == DUPLEX_FULL)
50 		return "Full";
51 	if (duplex == DUPLEX_UNKNOWN)
52 		return "Unknown";
53 	return "Unsupported (update phy-core.c)";
54 }
55 EXPORT_SYMBOL_GPL(phy_duplex_to_str);
56 
57 /* A mapping of all SUPPORTED settings to speed/duplex.  This table
58  * must be grouped by speed and sorted in descending match priority
59  * - iow, descending speed. */
60 static const struct phy_setting settings[] = {
61 	/* 100G */
62 	{
63 		.speed = SPEED_100000,
64 		.duplex = DUPLEX_FULL,
65 		.bit = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
66 	},
67 	{
68 		.speed = SPEED_100000,
69 		.duplex = DUPLEX_FULL,
70 		.bit = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
71 	},
72 	{
73 		.speed = SPEED_100000,
74 		.duplex = DUPLEX_FULL,
75 		.bit = ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
76 	},
77 	{
78 		.speed = SPEED_100000,
79 		.duplex = DUPLEX_FULL,
80 		.bit = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
81 	},
82 	/* 56G */
83 	{
84 		.speed = SPEED_56000,
85 		.duplex = DUPLEX_FULL,
86 		.bit = ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT,
87 	},
88 	{
89 		.speed = SPEED_56000,
90 		.duplex = DUPLEX_FULL,
91 		.bit = ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT,
92 	},
93 	{
94 		.speed = SPEED_56000,
95 		.duplex = DUPLEX_FULL,
96 		.bit = ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT,
97 	},
98 	{
99 		.speed = SPEED_56000,
100 		.duplex = DUPLEX_FULL,
101 		.bit = ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT,
102 	},
103 	/* 50G */
104 	{
105 		.speed = SPEED_50000,
106 		.duplex = DUPLEX_FULL,
107 		.bit = ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
108 	},
109 	{
110 		.speed = SPEED_50000,
111 		.duplex = DUPLEX_FULL,
112 		.bit = ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
113 	},
114 	{
115 		.speed = SPEED_50000,
116 		.duplex = DUPLEX_FULL,
117 		.bit = ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
118 	},
119 	/* 40G */
120 	{
121 		.speed = SPEED_40000,
122 		.duplex = DUPLEX_FULL,
123 		.bit = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
124 	},
125 	{
126 		.speed = SPEED_40000,
127 		.duplex = DUPLEX_FULL,
128 		.bit = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
129 	},
130 	{
131 		.speed = SPEED_40000,
132 		.duplex = DUPLEX_FULL,
133 		.bit = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
134 	},
135 	{
136 		.speed = SPEED_40000,
137 		.duplex = DUPLEX_FULL,
138 		.bit = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
139 	},
140 	/* 25G */
141 	{
142 		.speed = SPEED_25000,
143 		.duplex = DUPLEX_FULL,
144 		.bit = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
145 	},
146 	{
147 		.speed = SPEED_25000,
148 		.duplex = DUPLEX_FULL,
149 		.bit = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
150 	},
151 	{
152 		.speed = SPEED_25000,
153 		.duplex = DUPLEX_FULL,
154 		.bit = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
155 	},
156 
157 	/* 20G */
158 	{
159 		.speed = SPEED_20000,
160 		.duplex = DUPLEX_FULL,
161 		.bit = ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
162 	},
163 	{
164 		.speed = SPEED_20000,
165 		.duplex = DUPLEX_FULL,
166 		.bit = ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT,
167 	},
168 	/* 10G */
169 	{
170 		.speed = SPEED_10000,
171 		.duplex = DUPLEX_FULL,
172 		.bit = ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
173 	},
174 	{
175 		.speed = SPEED_10000,
176 		.duplex = DUPLEX_FULL,
177 		.bit = ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
178 	},
179 	{
180 		.speed = SPEED_10000,
181 		.duplex = DUPLEX_FULL,
182 		.bit = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
183 	},
184 	{
185 		.speed = SPEED_10000,
186 		.duplex = DUPLEX_FULL,
187 		.bit = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
188 	},
189 	{
190 		.speed = SPEED_10000,
191 		.duplex = DUPLEX_FULL,
192 		.bit = ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
193 	},
194 	{
195 		.speed = SPEED_10000,
196 		.duplex = DUPLEX_FULL,
197 		.bit = ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
198 	},
199 	{
200 		.speed = SPEED_10000,
201 		.duplex = DUPLEX_FULL,
202 		.bit = ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
203 	},
204 	{
205 		.speed = SPEED_10000,
206 		.duplex = DUPLEX_FULL,
207 		.bit = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
208 	},
209 	{
210 		.speed = SPEED_10000,
211 		.duplex = DUPLEX_FULL,
212 		.bit = ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
213 	},
214 	/* 5G */
215 	{
216 		.speed = SPEED_5000,
217 		.duplex = DUPLEX_FULL,
218 		.bit = ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
219 	},
220 
221 	/* 2.5G */
222 	{
223 		.speed = SPEED_2500,
224 		.duplex = DUPLEX_FULL,
225 		.bit = ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
226 	},
227 	{
228 		.speed = SPEED_2500,
229 		.duplex = DUPLEX_FULL,
230 		.bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
231 	},
232 	/* 1G */
233 	{
234 		.speed = SPEED_1000,
235 		.duplex = DUPLEX_FULL,
236 		.bit = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
237 	},
238 	{
239 		.speed = SPEED_1000,
240 		.duplex = DUPLEX_FULL,
241 		.bit = ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
242 	},
243 	{
244 		.speed = SPEED_1000,
245 		.duplex = DUPLEX_HALF,
246 		.bit = ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
247 	},
248 	{
249 		.speed = SPEED_1000,
250 		.duplex = DUPLEX_FULL,
251 		.bit = ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
252 	},
253 	/* 100M */
254 	{
255 		.speed = SPEED_100,
256 		.duplex = DUPLEX_FULL,
257 		.bit = ETHTOOL_LINK_MODE_100baseT_Full_BIT,
258 	},
259 	{
260 		.speed = SPEED_100,
261 		.duplex = DUPLEX_HALF,
262 		.bit = ETHTOOL_LINK_MODE_100baseT_Half_BIT,
263 	},
264 	/* 10M */
265 	{
266 		.speed = SPEED_10,
267 		.duplex = DUPLEX_FULL,
268 		.bit = ETHTOOL_LINK_MODE_10baseT_Full_BIT,
269 	},
270 	{
271 		.speed = SPEED_10,
272 		.duplex = DUPLEX_HALF,
273 		.bit = ETHTOOL_LINK_MODE_10baseT_Half_BIT,
274 	},
275 };
276 
277 /**
278  * phy_lookup_setting - lookup a PHY setting
279  * @speed: speed to match
280  * @duplex: duplex to match
281  * @mask: allowed link modes
282  * @exact: an exact match is required
283  *
284  * Search the settings array for a setting that matches the speed and
285  * duplex, and which is supported.
286  *
287  * If @exact is unset, either an exact match or %NULL for no match will
288  * be returned.
289  *
290  * If @exact is set, an exact match, the fastest supported setting at
291  * or below the specified speed, the slowest supported setting, or if
292  * they all fail, %NULL will be returned.
293  */
294 const struct phy_setting *
295 phy_lookup_setting(int speed, int duplex, const unsigned long *mask, bool exact)
296 {
297 	const struct phy_setting *p, *match = NULL, *last = NULL;
298 	int i;
299 
300 	for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
301 		if (p->bit < __ETHTOOL_LINK_MODE_MASK_NBITS &&
302 		    test_bit(p->bit, mask)) {
303 			last = p;
304 			if (p->speed == speed && p->duplex == duplex) {
305 				/* Exact match for speed and duplex */
306 				match = p;
307 				break;
308 			} else if (!exact) {
309 				if (!match && p->speed <= speed)
310 					/* Candidate */
311 					match = p;
312 
313 				if (p->speed < speed)
314 					break;
315 			}
316 		}
317 	}
318 
319 	if (!match && !exact)
320 		match = last;
321 
322 	return match;
323 }
324 EXPORT_SYMBOL_GPL(phy_lookup_setting);
325 
326 size_t phy_speeds(unsigned int *speeds, size_t size,
327 		  unsigned long *mask)
328 {
329 	size_t count;
330 	int i;
331 
332 	for (i = 0, count = 0; i < ARRAY_SIZE(settings) && count < size; i++)
333 		if (settings[i].bit < __ETHTOOL_LINK_MODE_MASK_NBITS &&
334 		    test_bit(settings[i].bit, mask) &&
335 		    (count == 0 || speeds[count - 1] != settings[i].speed))
336 			speeds[count++] = settings[i].speed;
337 
338 	return count;
339 }
340 
341 /**
342  * phy_resolve_aneg_linkmode - resolve the advertisements into phy settings
343  * @phydev: The phy_device struct
344  *
345  * Resolve our and the link partner advertisements into their corresponding
346  * speed and duplex. If full duplex was negotiated, extract the pause mode
347  * from the link partner mask.
348  */
349 void phy_resolve_aneg_linkmode(struct phy_device *phydev)
350 {
351 	__ETHTOOL_DECLARE_LINK_MODE_MASK(common);
352 
353 	linkmode_and(common, phydev->lp_advertising, phydev->advertising);
354 
355 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, common)) {
356 		phydev->speed = SPEED_10000;
357 		phydev->duplex = DUPLEX_FULL;
358 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
359 				     common)) {
360 		phydev->speed = SPEED_5000;
361 		phydev->duplex = DUPLEX_FULL;
362 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
363 				     common)) {
364 		phydev->speed = SPEED_2500;
365 		phydev->duplex = DUPLEX_FULL;
366 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
367 				     common)) {
368 		phydev->speed = SPEED_1000;
369 		phydev->duplex = DUPLEX_FULL;
370 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
371 				     common)) {
372 		phydev->speed = SPEED_1000;
373 		phydev->duplex = DUPLEX_HALF;
374 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
375 				     common)) {
376 		phydev->speed = SPEED_100;
377 		phydev->duplex = DUPLEX_FULL;
378 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
379 				     common)) {
380 		phydev->speed = SPEED_100;
381 		phydev->duplex = DUPLEX_HALF;
382 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
383 				     common)) {
384 		phydev->speed = SPEED_10;
385 		phydev->duplex = DUPLEX_FULL;
386 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
387 				     common)) {
388 		phydev->speed = SPEED_10;
389 		phydev->duplex = DUPLEX_HALF;
390 	}
391 
392 	if (phydev->duplex == DUPLEX_FULL) {
393 		phydev->pause = linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
394 						  phydev->lp_advertising);
395 		phydev->asym_pause = linkmode_test_bit(
396 			ETHTOOL_LINK_MODE_Asym_Pause_BIT,
397 			phydev->lp_advertising);
398 	}
399 }
400 EXPORT_SYMBOL_GPL(phy_resolve_aneg_linkmode);
401 
402 static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
403 			     u16 regnum)
404 {
405 	/* Write the desired MMD Devad */
406 	__mdiobus_write(bus, phy_addr, MII_MMD_CTRL, devad);
407 
408 	/* Write the desired MMD register address */
409 	__mdiobus_write(bus, phy_addr, MII_MMD_DATA, regnum);
410 
411 	/* Select the Function : DATA with no post increment */
412 	__mdiobus_write(bus, phy_addr, MII_MMD_CTRL,
413 			devad | MII_MMD_CTRL_NOINCR);
414 }
415 
416 /**
417  * phy_read_mmd - Convenience function for reading a register
418  * from an MMD on a given PHY.
419  * @phydev: The phy_device struct
420  * @devad: The MMD to read from (0..31)
421  * @regnum: The register on the MMD to read (0..65535)
422  *
423  * Same rules as for phy_read();
424  */
425 int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
426 {
427 	int val;
428 
429 	if (regnum > (u16)~0 || devad > 32)
430 		return -EINVAL;
431 
432 	if (phydev->drv->read_mmd) {
433 		val = phydev->drv->read_mmd(phydev, devad, regnum);
434 	} else if (phydev->is_c45) {
435 		u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
436 
437 		val = mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, addr);
438 	} else {
439 		struct mii_bus *bus = phydev->mdio.bus;
440 		int phy_addr = phydev->mdio.addr;
441 
442 		mutex_lock(&bus->mdio_lock);
443 		mmd_phy_indirect(bus, phy_addr, devad, regnum);
444 
445 		/* Read the content of the MMD's selected register */
446 		val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
447 		mutex_unlock(&bus->mdio_lock);
448 	}
449 	return val;
450 }
451 EXPORT_SYMBOL(phy_read_mmd);
452 
453 /**
454  * phy_write_mmd - Convenience function for writing a register
455  * on an MMD on a given PHY.
456  * @phydev: The phy_device struct
457  * @devad: The MMD to read from
458  * @regnum: The register on the MMD to read
459  * @val: value to write to @regnum
460  *
461  * Same rules as for phy_write();
462  */
463 int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
464 {
465 	int ret;
466 
467 	if (regnum > (u16)~0 || devad > 32)
468 		return -EINVAL;
469 
470 	if (phydev->drv->write_mmd) {
471 		ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
472 	} else if (phydev->is_c45) {
473 		u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
474 
475 		ret = mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
476 				    addr, val);
477 	} else {
478 		struct mii_bus *bus = phydev->mdio.bus;
479 		int phy_addr = phydev->mdio.addr;
480 
481 		mutex_lock(&bus->mdio_lock);
482 		mmd_phy_indirect(bus, phy_addr, devad, regnum);
483 
484 		/* Write the data into MMD's selected register */
485 		__mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
486 		mutex_unlock(&bus->mdio_lock);
487 
488 		ret = 0;
489 	}
490 	return ret;
491 }
492 EXPORT_SYMBOL(phy_write_mmd);
493 
494 /**
495  * __phy_modify() - Convenience function for modifying a PHY register
496  * @phydev: a pointer to a &struct phy_device
497  * @regnum: register number
498  * @mask: bit mask of bits to clear
499  * @set: bit mask of bits to set
500  *
501  * Unlocked helper function which allows a PHY register to be modified as
502  * new register value = (old register value & ~mask) | set
503  */
504 int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
505 {
506 	int ret;
507 
508 	ret = __phy_read(phydev, regnum);
509 	if (ret < 0)
510 		return ret;
511 
512 	ret = __phy_write(phydev, regnum, (ret & ~mask) | set);
513 
514 	return ret < 0 ? ret : 0;
515 }
516 EXPORT_SYMBOL_GPL(__phy_modify);
517 
518 /**
519  * phy_modify - Convenience function for modifying a given PHY register
520  * @phydev: the phy_device struct
521  * @regnum: register number to write
522  * @mask: bit mask of bits to clear
523  * @set: new value of bits set in mask to write to @regnum
524  *
525  * NOTE: MUST NOT be called from interrupt context,
526  * because the bus read/write functions may wait for an interrupt
527  * to conclude the operation.
528  */
529 int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
530 {
531 	int ret;
532 
533 	mutex_lock(&phydev->mdio.bus->mdio_lock);
534 	ret = __phy_modify(phydev, regnum, mask, set);
535 	mutex_unlock(&phydev->mdio.bus->mdio_lock);
536 
537 	return ret;
538 }
539 EXPORT_SYMBOL_GPL(phy_modify);
540 
541 static int __phy_read_page(struct phy_device *phydev)
542 {
543 	return phydev->drv->read_page(phydev);
544 }
545 
546 static int __phy_write_page(struct phy_device *phydev, int page)
547 {
548 	return phydev->drv->write_page(phydev, page);
549 }
550 
551 /**
552  * phy_save_page() - take the bus lock and save the current page
553  * @phydev: a pointer to a &struct phy_device
554  *
555  * Take the MDIO bus lock, and return the current page number. On error,
556  * returns a negative errno. phy_restore_page() must always be called
557  * after this, irrespective of success or failure of this call.
558  */
559 int phy_save_page(struct phy_device *phydev)
560 {
561 	mutex_lock(&phydev->mdio.bus->mdio_lock);
562 	return __phy_read_page(phydev);
563 }
564 EXPORT_SYMBOL_GPL(phy_save_page);
565 
566 /**
567  * phy_select_page() - take the bus lock, save the current page, and set a page
568  * @phydev: a pointer to a &struct phy_device
569  * @page: desired page
570  *
571  * Take the MDIO bus lock to protect against concurrent access, save the
572  * current PHY page, and set the current page.  On error, returns a
573  * negative errno, otherwise returns the previous page number.
574  * phy_restore_page() must always be called after this, irrespective
575  * of success or failure of this call.
576  */
577 int phy_select_page(struct phy_device *phydev, int page)
578 {
579 	int ret, oldpage;
580 
581 	oldpage = ret = phy_save_page(phydev);
582 	if (ret < 0)
583 		return ret;
584 
585 	if (oldpage != page) {
586 		ret = __phy_write_page(phydev, page);
587 		if (ret < 0)
588 			return ret;
589 	}
590 
591 	return oldpage;
592 }
593 EXPORT_SYMBOL_GPL(phy_select_page);
594 
595 /**
596  * phy_restore_page() - restore the page register and release the bus lock
597  * @phydev: a pointer to a &struct phy_device
598  * @oldpage: the old page, return value from phy_save_page() or phy_select_page()
599  * @ret: operation's return code
600  *
601  * Release the MDIO bus lock, restoring @oldpage if it is a valid page.
602  * This function propagates the earliest error code from the group of
603  * operations.
604  *
605  * Returns:
606  *   @oldpage if it was a negative value, otherwise
607  *   @ret if it was a negative errno value, otherwise
608  *   phy_write_page()'s negative value if it were in error, otherwise
609  *   @ret.
610  */
611 int phy_restore_page(struct phy_device *phydev, int oldpage, int ret)
612 {
613 	int r;
614 
615 	if (oldpage >= 0) {
616 		r = __phy_write_page(phydev, oldpage);
617 
618 		/* Propagate the operation return code if the page write
619 		 * was successful.
620 		 */
621 		if (ret >= 0 && r < 0)
622 			ret = r;
623 	} else {
624 		/* Propagate the phy page selection error code */
625 		ret = oldpage;
626 	}
627 
628 	mutex_unlock(&phydev->mdio.bus->mdio_lock);
629 
630 	return ret;
631 }
632 EXPORT_SYMBOL_GPL(phy_restore_page);
633 
634 /**
635  * phy_read_paged() - Convenience function for reading a paged register
636  * @phydev: a pointer to a &struct phy_device
637  * @page: the page for the phy
638  * @regnum: register number
639  *
640  * Same rules as for phy_read().
641  */
642 int phy_read_paged(struct phy_device *phydev, int page, u32 regnum)
643 {
644 	int ret = 0, oldpage;
645 
646 	oldpage = phy_select_page(phydev, page);
647 	if (oldpage >= 0)
648 		ret = __phy_read(phydev, regnum);
649 
650 	return phy_restore_page(phydev, oldpage, ret);
651 }
652 EXPORT_SYMBOL(phy_read_paged);
653 
654 /**
655  * phy_write_paged() - Convenience function for writing a paged register
656  * @phydev: a pointer to a &struct phy_device
657  * @page: the page for the phy
658  * @regnum: register number
659  * @val: value to write
660  *
661  * Same rules as for phy_write().
662  */
663 int phy_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val)
664 {
665 	int ret = 0, oldpage;
666 
667 	oldpage = phy_select_page(phydev, page);
668 	if (oldpage >= 0)
669 		ret = __phy_write(phydev, regnum, val);
670 
671 	return phy_restore_page(phydev, oldpage, ret);
672 }
673 EXPORT_SYMBOL(phy_write_paged);
674 
675 /**
676  * phy_modify_paged() - Convenience function for modifying a paged register
677  * @phydev: a pointer to a &struct phy_device
678  * @page: the page for the phy
679  * @regnum: register number
680  * @mask: bit mask of bits to clear
681  * @set: bit mask of bits to set
682  *
683  * Same rules as for phy_read() and phy_write().
684  */
685 int phy_modify_paged(struct phy_device *phydev, int page, u32 regnum,
686 		     u16 mask, u16 set)
687 {
688 	int ret = 0, oldpage;
689 
690 	oldpage = phy_select_page(phydev, page);
691 	if (oldpage >= 0)
692 		ret = __phy_modify(phydev, regnum, mask, set);
693 
694 	return phy_restore_page(phydev, oldpage, ret);
695 }
696 EXPORT_SYMBOL(phy_modify_paged);
697