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