0001
0002
0003
0004
0005 #include <linux/export.h>
0006 #include <linux/phy.h>
0007 #include <linux/of.h>
0008
0009
0010
0011
0012
0013
0014 const char *phy_speed_to_str(int speed)
0015 {
0016 BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 93,
0017 "Enum ethtool_link_mode_bit_indices and phylib are out of sync. "
0018 "If a speed or mode has been added please update phy_speed_to_str "
0019 "and the PHY settings array.\n");
0020
0021 switch (speed) {
0022 case SPEED_10:
0023 return "10Mbps";
0024 case SPEED_100:
0025 return "100Mbps";
0026 case SPEED_1000:
0027 return "1Gbps";
0028 case SPEED_2500:
0029 return "2.5Gbps";
0030 case SPEED_5000:
0031 return "5Gbps";
0032 case SPEED_10000:
0033 return "10Gbps";
0034 case SPEED_14000:
0035 return "14Gbps";
0036 case SPEED_20000:
0037 return "20Gbps";
0038 case SPEED_25000:
0039 return "25Gbps";
0040 case SPEED_40000:
0041 return "40Gbps";
0042 case SPEED_50000:
0043 return "50Gbps";
0044 case SPEED_56000:
0045 return "56Gbps";
0046 case SPEED_100000:
0047 return "100Gbps";
0048 case SPEED_200000:
0049 return "200Gbps";
0050 case SPEED_400000:
0051 return "400Gbps";
0052 case SPEED_UNKNOWN:
0053 return "Unknown";
0054 default:
0055 return "Unsupported (update phy-core.c)";
0056 }
0057 }
0058 EXPORT_SYMBOL_GPL(phy_speed_to_str);
0059
0060
0061
0062
0063
0064
0065 const char *phy_duplex_to_str(unsigned int duplex)
0066 {
0067 if (duplex == DUPLEX_HALF)
0068 return "Half";
0069 if (duplex == DUPLEX_FULL)
0070 return "Full";
0071 if (duplex == DUPLEX_UNKNOWN)
0072 return "Unknown";
0073 return "Unsupported (update phy-core.c)";
0074 }
0075 EXPORT_SYMBOL_GPL(phy_duplex_to_str);
0076
0077
0078
0079
0080
0081
0082 #define PHY_SETTING(s, d, b) { .speed = SPEED_ ## s, .duplex = DUPLEX_ ## d, \
0083 .bit = ETHTOOL_LINK_MODE_ ## b ## _BIT}
0084
0085 static const struct phy_setting settings[] = {
0086
0087 PHY_SETTING( 400000, FULL, 400000baseCR8_Full ),
0088 PHY_SETTING( 400000, FULL, 400000baseKR8_Full ),
0089 PHY_SETTING( 400000, FULL, 400000baseLR8_ER8_FR8_Full ),
0090 PHY_SETTING( 400000, FULL, 400000baseDR8_Full ),
0091 PHY_SETTING( 400000, FULL, 400000baseSR8_Full ),
0092 PHY_SETTING( 400000, FULL, 400000baseCR4_Full ),
0093 PHY_SETTING( 400000, FULL, 400000baseKR4_Full ),
0094 PHY_SETTING( 400000, FULL, 400000baseLR4_ER4_FR4_Full ),
0095 PHY_SETTING( 400000, FULL, 400000baseDR4_Full ),
0096 PHY_SETTING( 400000, FULL, 400000baseSR4_Full ),
0097
0098 PHY_SETTING( 200000, FULL, 200000baseCR4_Full ),
0099 PHY_SETTING( 200000, FULL, 200000baseKR4_Full ),
0100 PHY_SETTING( 200000, FULL, 200000baseLR4_ER4_FR4_Full ),
0101 PHY_SETTING( 200000, FULL, 200000baseDR4_Full ),
0102 PHY_SETTING( 200000, FULL, 200000baseSR4_Full ),
0103 PHY_SETTING( 200000, FULL, 200000baseCR2_Full ),
0104 PHY_SETTING( 200000, FULL, 200000baseKR2_Full ),
0105 PHY_SETTING( 200000, FULL, 200000baseLR2_ER2_FR2_Full ),
0106 PHY_SETTING( 200000, FULL, 200000baseDR2_Full ),
0107 PHY_SETTING( 200000, FULL, 200000baseSR2_Full ),
0108
0109 PHY_SETTING( 100000, FULL, 100000baseCR4_Full ),
0110 PHY_SETTING( 100000, FULL, 100000baseKR4_Full ),
0111 PHY_SETTING( 100000, FULL, 100000baseLR4_ER4_Full ),
0112 PHY_SETTING( 100000, FULL, 100000baseSR4_Full ),
0113 PHY_SETTING( 100000, FULL, 100000baseCR2_Full ),
0114 PHY_SETTING( 100000, FULL, 100000baseKR2_Full ),
0115 PHY_SETTING( 100000, FULL, 100000baseLR2_ER2_FR2_Full ),
0116 PHY_SETTING( 100000, FULL, 100000baseDR2_Full ),
0117 PHY_SETTING( 100000, FULL, 100000baseSR2_Full ),
0118 PHY_SETTING( 100000, FULL, 100000baseCR_Full ),
0119 PHY_SETTING( 100000, FULL, 100000baseKR_Full ),
0120 PHY_SETTING( 100000, FULL, 100000baseLR_ER_FR_Full ),
0121 PHY_SETTING( 100000, FULL, 100000baseDR_Full ),
0122 PHY_SETTING( 100000, FULL, 100000baseSR_Full ),
0123
0124 PHY_SETTING( 56000, FULL, 56000baseCR4_Full ),
0125 PHY_SETTING( 56000, FULL, 56000baseKR4_Full ),
0126 PHY_SETTING( 56000, FULL, 56000baseLR4_Full ),
0127 PHY_SETTING( 56000, FULL, 56000baseSR4_Full ),
0128
0129 PHY_SETTING( 50000, FULL, 50000baseCR2_Full ),
0130 PHY_SETTING( 50000, FULL, 50000baseKR2_Full ),
0131 PHY_SETTING( 50000, FULL, 50000baseSR2_Full ),
0132 PHY_SETTING( 50000, FULL, 50000baseCR_Full ),
0133 PHY_SETTING( 50000, FULL, 50000baseKR_Full ),
0134 PHY_SETTING( 50000, FULL, 50000baseLR_ER_FR_Full ),
0135 PHY_SETTING( 50000, FULL, 50000baseDR_Full ),
0136 PHY_SETTING( 50000, FULL, 50000baseSR_Full ),
0137
0138 PHY_SETTING( 40000, FULL, 40000baseCR4_Full ),
0139 PHY_SETTING( 40000, FULL, 40000baseKR4_Full ),
0140 PHY_SETTING( 40000, FULL, 40000baseLR4_Full ),
0141 PHY_SETTING( 40000, FULL, 40000baseSR4_Full ),
0142
0143 PHY_SETTING( 25000, FULL, 25000baseCR_Full ),
0144 PHY_SETTING( 25000, FULL, 25000baseKR_Full ),
0145 PHY_SETTING( 25000, FULL, 25000baseSR_Full ),
0146
0147 PHY_SETTING( 20000, FULL, 20000baseKR2_Full ),
0148 PHY_SETTING( 20000, FULL, 20000baseMLD2_Full ),
0149
0150 PHY_SETTING( 10000, FULL, 10000baseCR_Full ),
0151 PHY_SETTING( 10000, FULL, 10000baseER_Full ),
0152 PHY_SETTING( 10000, FULL, 10000baseKR_Full ),
0153 PHY_SETTING( 10000, FULL, 10000baseKX4_Full ),
0154 PHY_SETTING( 10000, FULL, 10000baseLR_Full ),
0155 PHY_SETTING( 10000, FULL, 10000baseLRM_Full ),
0156 PHY_SETTING( 10000, FULL, 10000baseR_FEC ),
0157 PHY_SETTING( 10000, FULL, 10000baseSR_Full ),
0158 PHY_SETTING( 10000, FULL, 10000baseT_Full ),
0159
0160 PHY_SETTING( 5000, FULL, 5000baseT_Full ),
0161
0162 PHY_SETTING( 2500, FULL, 2500baseT_Full ),
0163 PHY_SETTING( 2500, FULL, 2500baseX_Full ),
0164
0165 PHY_SETTING( 1000, FULL, 1000baseT_Full ),
0166 PHY_SETTING( 1000, HALF, 1000baseT_Half ),
0167 PHY_SETTING( 1000, FULL, 1000baseT1_Full ),
0168 PHY_SETTING( 1000, FULL, 1000baseX_Full ),
0169 PHY_SETTING( 1000, FULL, 1000baseKX_Full ),
0170
0171 PHY_SETTING( 100, FULL, 100baseT_Full ),
0172 PHY_SETTING( 100, FULL, 100baseT1_Full ),
0173 PHY_SETTING( 100, HALF, 100baseT_Half ),
0174 PHY_SETTING( 100, HALF, 100baseFX_Half ),
0175 PHY_SETTING( 100, FULL, 100baseFX_Full ),
0176
0177 PHY_SETTING( 10, FULL, 10baseT_Full ),
0178 PHY_SETTING( 10, HALF, 10baseT_Half ),
0179 PHY_SETTING( 10, FULL, 10baseT1L_Full ),
0180 };
0181 #undef PHY_SETTING
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200 const struct phy_setting *
0201 phy_lookup_setting(int speed, int duplex, const unsigned long *mask, bool exact)
0202 {
0203 const struct phy_setting *p, *match = NULL, *last = NULL;
0204 int i;
0205
0206 for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
0207 if (p->bit < __ETHTOOL_LINK_MODE_MASK_NBITS &&
0208 test_bit(p->bit, mask)) {
0209 last = p;
0210 if (p->speed == speed && p->duplex == duplex) {
0211
0212 match = p;
0213 break;
0214 } else if (!exact) {
0215 if (!match && p->speed <= speed)
0216
0217 match = p;
0218
0219 if (p->speed < speed)
0220 break;
0221 }
0222 }
0223 }
0224
0225 if (!match && !exact)
0226 match = last;
0227
0228 return match;
0229 }
0230 EXPORT_SYMBOL_GPL(phy_lookup_setting);
0231
0232 size_t phy_speeds(unsigned int *speeds, size_t size,
0233 unsigned long *mask)
0234 {
0235 size_t count;
0236 int i;
0237
0238 for (i = 0, count = 0; i < ARRAY_SIZE(settings) && count < size; i++)
0239 if (settings[i].bit < __ETHTOOL_LINK_MODE_MASK_NBITS &&
0240 test_bit(settings[i].bit, mask) &&
0241 (count == 0 || speeds[count - 1] != settings[i].speed))
0242 speeds[count++] = settings[i].speed;
0243
0244 return count;
0245 }
0246
0247 static void __set_linkmode_max_speed(u32 max_speed, unsigned long *addr)
0248 {
0249 const struct phy_setting *p;
0250 int i;
0251
0252 for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
0253 if (p->speed > max_speed)
0254 linkmode_clear_bit(p->bit, addr);
0255 else
0256 break;
0257 }
0258 }
0259
0260 static void __set_phy_supported(struct phy_device *phydev, u32 max_speed)
0261 {
0262 __set_linkmode_max_speed(max_speed, phydev->supported);
0263 }
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275 void phy_set_max_speed(struct phy_device *phydev, u32 max_speed)
0276 {
0277 __set_phy_supported(phydev, max_speed);
0278
0279 phy_advertise_supported(phydev);
0280 }
0281 EXPORT_SYMBOL(phy_set_max_speed);
0282
0283 void of_set_phy_supported(struct phy_device *phydev)
0284 {
0285 struct device_node *node = phydev->mdio.dev.of_node;
0286 u32 max_speed;
0287
0288 if (!IS_ENABLED(CONFIG_OF_MDIO))
0289 return;
0290
0291 if (!node)
0292 return;
0293
0294 if (!of_property_read_u32(node, "max-speed", &max_speed))
0295 __set_phy_supported(phydev, max_speed);
0296 }
0297
0298 void of_set_phy_eee_broken(struct phy_device *phydev)
0299 {
0300 struct device_node *node = phydev->mdio.dev.of_node;
0301 u32 broken = 0;
0302
0303 if (!IS_ENABLED(CONFIG_OF_MDIO))
0304 return;
0305
0306 if (!node)
0307 return;
0308
0309 if (of_property_read_bool(node, "eee-broken-100tx"))
0310 broken |= MDIO_EEE_100TX;
0311 if (of_property_read_bool(node, "eee-broken-1000t"))
0312 broken |= MDIO_EEE_1000T;
0313 if (of_property_read_bool(node, "eee-broken-10gt"))
0314 broken |= MDIO_EEE_10GT;
0315 if (of_property_read_bool(node, "eee-broken-1000kx"))
0316 broken |= MDIO_EEE_1000KX;
0317 if (of_property_read_bool(node, "eee-broken-10gkx4"))
0318 broken |= MDIO_EEE_10GKX4;
0319 if (of_property_read_bool(node, "eee-broken-10gkr"))
0320 broken |= MDIO_EEE_10GKR;
0321
0322 phydev->eee_broken_modes = broken;
0323 }
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335 void phy_resolve_aneg_pause(struct phy_device *phydev)
0336 {
0337 if (phydev->duplex == DUPLEX_FULL) {
0338 phydev->pause = linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
0339 phydev->lp_advertising);
0340 phydev->asym_pause = linkmode_test_bit(
0341 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
0342 phydev->lp_advertising);
0343 }
0344 }
0345 EXPORT_SYMBOL_GPL(phy_resolve_aneg_pause);
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355 void phy_resolve_aneg_linkmode(struct phy_device *phydev)
0356 {
0357 __ETHTOOL_DECLARE_LINK_MODE_MASK(common);
0358 int i;
0359
0360 linkmode_and(common, phydev->lp_advertising, phydev->advertising);
0361
0362 for (i = 0; i < ARRAY_SIZE(settings); i++)
0363 if (test_bit(settings[i].bit, common)) {
0364 phydev->speed = settings[i].speed;
0365 phydev->duplex = settings[i].duplex;
0366 break;
0367 }
0368
0369 phy_resolve_aneg_pause(phydev);
0370 }
0371 EXPORT_SYMBOL_GPL(phy_resolve_aneg_linkmode);
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382 void phy_check_downshift(struct phy_device *phydev)
0383 {
0384 __ETHTOOL_DECLARE_LINK_MODE_MASK(common);
0385 int i, speed = SPEED_UNKNOWN;
0386
0387 phydev->downshifted_rate = 0;
0388
0389 if (phydev->autoneg == AUTONEG_DISABLE ||
0390 phydev->speed == SPEED_UNKNOWN)
0391 return;
0392
0393 linkmode_and(common, phydev->lp_advertising, phydev->advertising);
0394
0395 for (i = 0; i < ARRAY_SIZE(settings); i++)
0396 if (test_bit(settings[i].bit, common)) {
0397 speed = settings[i].speed;
0398 break;
0399 }
0400
0401 if (speed == SPEED_UNKNOWN || phydev->speed >= speed)
0402 return;
0403
0404 phydev_warn(phydev, "Downshift occurred from negotiated speed %s to actual speed %s, check cabling!\n",
0405 phy_speed_to_str(speed), phy_speed_to_str(phydev->speed));
0406
0407 phydev->downshifted_rate = 1;
0408 }
0409 EXPORT_SYMBOL_GPL(phy_check_downshift);
0410
0411 static int phy_resolve_min_speed(struct phy_device *phydev, bool fdx_only)
0412 {
0413 __ETHTOOL_DECLARE_LINK_MODE_MASK(common);
0414 int i = ARRAY_SIZE(settings);
0415
0416 linkmode_and(common, phydev->lp_advertising, phydev->advertising);
0417
0418 while (--i >= 0) {
0419 if (test_bit(settings[i].bit, common)) {
0420 if (fdx_only && settings[i].duplex != DUPLEX_FULL)
0421 continue;
0422 return settings[i].speed;
0423 }
0424 }
0425
0426 return SPEED_UNKNOWN;
0427 }
0428
0429 int phy_speed_down_core(struct phy_device *phydev)
0430 {
0431 int min_common_speed = phy_resolve_min_speed(phydev, true);
0432
0433 if (min_common_speed == SPEED_UNKNOWN)
0434 return -EINVAL;
0435
0436 __set_linkmode_max_speed(min_common_speed, phydev->advertising);
0437
0438 return 0;
0439 }
0440
0441 static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
0442 u16 regnum)
0443 {
0444
0445 __mdiobus_write(bus, phy_addr, MII_MMD_CTRL, devad);
0446
0447
0448 __mdiobus_write(bus, phy_addr, MII_MMD_DATA, regnum);
0449
0450
0451 __mdiobus_write(bus, phy_addr, MII_MMD_CTRL,
0452 devad | MII_MMD_CTRL_NOINCR);
0453 }
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464 int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
0465 {
0466 int val;
0467
0468 if (regnum > (u16)~0 || devad > 32)
0469 return -EINVAL;
0470
0471 if (phydev->drv && phydev->drv->read_mmd) {
0472 val = phydev->drv->read_mmd(phydev, devad, regnum);
0473 } else if (phydev->is_c45) {
0474 val = __mdiobus_c45_read(phydev->mdio.bus, phydev->mdio.addr,
0475 devad, regnum);
0476 } else {
0477 struct mii_bus *bus = phydev->mdio.bus;
0478 int phy_addr = phydev->mdio.addr;
0479
0480 mmd_phy_indirect(bus, phy_addr, devad, regnum);
0481
0482
0483 val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
0484 }
0485 return val;
0486 }
0487 EXPORT_SYMBOL(__phy_read_mmd);
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498 int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
0499 {
0500 int ret;
0501
0502 phy_lock_mdio_bus(phydev);
0503 ret = __phy_read_mmd(phydev, devad, regnum);
0504 phy_unlock_mdio_bus(phydev);
0505
0506 return ret;
0507 }
0508 EXPORT_SYMBOL(phy_read_mmd);
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520 int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
0521 {
0522 int ret;
0523
0524 if (regnum > (u16)~0 || devad > 32)
0525 return -EINVAL;
0526
0527 if (phydev->drv && phydev->drv->write_mmd) {
0528 ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
0529 } else if (phydev->is_c45) {
0530 ret = __mdiobus_c45_write(phydev->mdio.bus, phydev->mdio.addr,
0531 devad, regnum, val);
0532 } else {
0533 struct mii_bus *bus = phydev->mdio.bus;
0534 int phy_addr = phydev->mdio.addr;
0535
0536 mmd_phy_indirect(bus, phy_addr, devad, regnum);
0537
0538
0539 __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
0540
0541 ret = 0;
0542 }
0543 return ret;
0544 }
0545 EXPORT_SYMBOL(__phy_write_mmd);
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557 int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
0558 {
0559 int ret;
0560
0561 phy_lock_mdio_bus(phydev);
0562 ret = __phy_write_mmd(phydev, devad, regnum, val);
0563 phy_unlock_mdio_bus(phydev);
0564
0565 return ret;
0566 }
0567 EXPORT_SYMBOL(phy_write_mmd);
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582 int phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
0583 {
0584 int ret;
0585
0586 phy_lock_mdio_bus(phydev);
0587 ret = __phy_modify_changed(phydev, regnum, mask, set);
0588 phy_unlock_mdio_bus(phydev);
0589
0590 return ret;
0591 }
0592 EXPORT_SYMBOL_GPL(phy_modify_changed);
0593
0594
0595
0596
0597
0598
0599
0600
0601
0602
0603
0604
0605 int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
0606 {
0607 int ret;
0608
0609 ret = __phy_modify_changed(phydev, regnum, mask, set);
0610
0611 return ret < 0 ? ret : 0;
0612 }
0613 EXPORT_SYMBOL_GPL(__phy_modify);
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626 int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
0627 {
0628 int ret;
0629
0630 phy_lock_mdio_bus(phydev);
0631 ret = __phy_modify(phydev, regnum, mask, set);
0632 phy_unlock_mdio_bus(phydev);
0633
0634 return ret;
0635 }
0636 EXPORT_SYMBOL_GPL(phy_modify);
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648
0649
0650
0651 int __phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
0652 u16 mask, u16 set)
0653 {
0654 int new, ret;
0655
0656 ret = __phy_read_mmd(phydev, devad, regnum);
0657 if (ret < 0)
0658 return ret;
0659
0660 new = (ret & ~mask) | set;
0661 if (new == ret)
0662 return 0;
0663
0664 ret = __phy_write_mmd(phydev, devad, regnum, new);
0665
0666 return ret < 0 ? ret : 1;
0667 }
0668 EXPORT_SYMBOL_GPL(__phy_modify_mmd_changed);
0669
0670
0671
0672
0673
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684 int phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
0685 u16 mask, u16 set)
0686 {
0687 int ret;
0688
0689 phy_lock_mdio_bus(phydev);
0690 ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set);
0691 phy_unlock_mdio_bus(phydev);
0692
0693 return ret;
0694 }
0695 EXPORT_SYMBOL_GPL(phy_modify_mmd_changed);
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709 int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
0710 u16 mask, u16 set)
0711 {
0712 int ret;
0713
0714 ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set);
0715
0716 return ret < 0 ? ret : 0;
0717 }
0718 EXPORT_SYMBOL_GPL(__phy_modify_mmd);
0719
0720
0721
0722
0723
0724
0725
0726
0727
0728
0729
0730
0731
0732 int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
0733 u16 mask, u16 set)
0734 {
0735 int ret;
0736
0737 phy_lock_mdio_bus(phydev);
0738 ret = __phy_modify_mmd(phydev, devad, regnum, mask, set);
0739 phy_unlock_mdio_bus(phydev);
0740
0741 return ret;
0742 }
0743 EXPORT_SYMBOL_GPL(phy_modify_mmd);
0744
0745 static int __phy_read_page(struct phy_device *phydev)
0746 {
0747 if (WARN_ONCE(!phydev->drv->read_page, "read_page callback not available, PHY driver not loaded?\n"))
0748 return -EOPNOTSUPP;
0749
0750 return phydev->drv->read_page(phydev);
0751 }
0752
0753 static int __phy_write_page(struct phy_device *phydev, int page)
0754 {
0755 if (WARN_ONCE(!phydev->drv->write_page, "write_page callback not available, PHY driver not loaded?\n"))
0756 return -EOPNOTSUPP;
0757
0758 return phydev->drv->write_page(phydev, page);
0759 }
0760
0761
0762
0763
0764
0765
0766
0767
0768
0769 int phy_save_page(struct phy_device *phydev)
0770 {
0771 phy_lock_mdio_bus(phydev);
0772 return __phy_read_page(phydev);
0773 }
0774 EXPORT_SYMBOL_GPL(phy_save_page);
0775
0776
0777
0778
0779
0780
0781
0782
0783
0784
0785
0786
0787 int phy_select_page(struct phy_device *phydev, int page)
0788 {
0789 int ret, oldpage;
0790
0791 oldpage = ret = phy_save_page(phydev);
0792 if (ret < 0)
0793 return ret;
0794
0795 if (oldpage != page) {
0796 ret = __phy_write_page(phydev, page);
0797 if (ret < 0)
0798 return ret;
0799 }
0800
0801 return oldpage;
0802 }
0803 EXPORT_SYMBOL_GPL(phy_select_page);
0804
0805
0806
0807
0808
0809
0810
0811
0812
0813
0814
0815
0816
0817
0818
0819
0820
0821 int phy_restore_page(struct phy_device *phydev, int oldpage, int ret)
0822 {
0823 int r;
0824
0825 if (oldpage >= 0) {
0826 r = __phy_write_page(phydev, oldpage);
0827
0828
0829
0830
0831 if (ret >= 0 && r < 0)
0832 ret = r;
0833 } else {
0834
0835 ret = oldpage;
0836 }
0837
0838 phy_unlock_mdio_bus(phydev);
0839
0840 return ret;
0841 }
0842 EXPORT_SYMBOL_GPL(phy_restore_page);
0843
0844
0845
0846
0847
0848
0849
0850
0851
0852 int phy_read_paged(struct phy_device *phydev, int page, u32 regnum)
0853 {
0854 int ret = 0, oldpage;
0855
0856 oldpage = phy_select_page(phydev, page);
0857 if (oldpage >= 0)
0858 ret = __phy_read(phydev, regnum);
0859
0860 return phy_restore_page(phydev, oldpage, ret);
0861 }
0862 EXPORT_SYMBOL(phy_read_paged);
0863
0864
0865
0866
0867
0868
0869
0870
0871
0872
0873 int phy_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val)
0874 {
0875 int ret = 0, oldpage;
0876
0877 oldpage = phy_select_page(phydev, page);
0878 if (oldpage >= 0)
0879 ret = __phy_write(phydev, regnum, val);
0880
0881 return phy_restore_page(phydev, oldpage, ret);
0882 }
0883 EXPORT_SYMBOL(phy_write_paged);
0884
0885
0886
0887
0888
0889
0890
0891
0892
0893
0894
0895 int phy_modify_paged_changed(struct phy_device *phydev, int page, u32 regnum,
0896 u16 mask, u16 set)
0897 {
0898 int ret = 0, oldpage;
0899
0900 oldpage = phy_select_page(phydev, page);
0901 if (oldpage >= 0)
0902 ret = __phy_modify_changed(phydev, regnum, mask, set);
0903
0904 return phy_restore_page(phydev, oldpage, ret);
0905 }
0906 EXPORT_SYMBOL(phy_modify_paged_changed);
0907
0908
0909
0910
0911
0912
0913
0914
0915
0916
0917
0918 int phy_modify_paged(struct phy_device *phydev, int page, u32 regnum,
0919 u16 mask, u16 set)
0920 {
0921 int ret = phy_modify_paged_changed(phydev, page, regnum, mask, set);
0922
0923 return ret < 0 ? ret : 0;
0924 }
0925 EXPORT_SYMBOL(phy_modify_paged);