aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/phy.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2019-05-28 05:57:29 -0400
committerDavid S. Miller <davem@davemloft.net>2019-05-31 15:37:46 -0400
commitcdea04c24616416f8239d86a1012d924fb6f0d30 (patch)
tree76eaf93f06441081b2b74d70c9d4198b7460f56d /drivers/net/phy/phy.c
parent7b3b0e89bcf3acb56bf59666122226de0913a8b4 (diff)
net: phy: allow Clause 45 access via mii ioctl
Allow userspace to generate Clause 45 MII access cycles via phylib. This is useful for tools such as mii-diag to be able to inspect Clause 45 PHYs. Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy/phy.c')
-rw-r--r--drivers/net/phy/phy.c33
1 files changed, 24 insertions, 9 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 84671d868a80..0084220d10dc 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -409,6 +409,7 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
409 struct mii_ioctl_data *mii_data = if_mii(ifr); 409 struct mii_ioctl_data *mii_data = if_mii(ifr);
410 u16 val = mii_data->val_in; 410 u16 val = mii_data->val_in;
411 bool change_autoneg = false; 411 bool change_autoneg = false;
412 int prtad, devad;
412 413
413 switch (cmd) { 414 switch (cmd) {
414 case SIOCGMIIPHY: 415 case SIOCGMIIPHY:
@@ -416,14 +417,29 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
416 /* fall through */ 417 /* fall through */
417 418
418 case SIOCGMIIREG: 419 case SIOCGMIIREG:
419 mii_data->val_out = mdiobus_read(phydev->mdio.bus, 420 if (mdio_phy_id_is_c45(mii_data->phy_id)) {
420 mii_data->phy_id, 421 prtad = mdio_phy_id_prtad(mii_data->phy_id);
421 mii_data->reg_num); 422 devad = mdio_phy_id_devad(mii_data->phy_id);
423 devad = MII_ADDR_C45 | devad << 16 | mii_data->reg_num;
424 } else {
425 prtad = mii_data->phy_id;
426 devad = mii_data->reg_num;
427 }
428 mii_data->val_out = mdiobus_read(phydev->mdio.bus, prtad,
429 devad);
422 return 0; 430 return 0;
423 431
424 case SIOCSMIIREG: 432 case SIOCSMIIREG:
425 if (mii_data->phy_id == phydev->mdio.addr) { 433 if (mdio_phy_id_is_c45(mii_data->phy_id)) {
426 switch (mii_data->reg_num) { 434 prtad = mdio_phy_id_prtad(mii_data->phy_id);
435 devad = mdio_phy_id_devad(mii_data->phy_id);
436 devad = MII_ADDR_C45 | devad << 16 | mii_data->reg_num;
437 } else {
438 prtad = mii_data->phy_id;
439 devad = mii_data->reg_num;
440 }
441 if (prtad == phydev->mdio.addr) {
442 switch (devad) {
427 case MII_BMCR: 443 case MII_BMCR:
428 if ((val & (BMCR_RESET | BMCR_ANENABLE)) == 0) { 444 if ((val & (BMCR_RESET | BMCR_ANENABLE)) == 0) {
429 if (phydev->autoneg == AUTONEG_ENABLE) 445 if (phydev->autoneg == AUTONEG_ENABLE)
@@ -456,11 +472,10 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
456 } 472 }
457 } 473 }
458 474
459 mdiobus_write(phydev->mdio.bus, mii_data->phy_id, 475 mdiobus_write(phydev->mdio.bus, prtad, devad, val);
460 mii_data->reg_num, val);
461 476
462 if (mii_data->phy_id == phydev->mdio.addr && 477 if (prtad == phydev->mdio.addr &&
463 mii_data->reg_num == MII_BMCR && 478 devad == MII_BMCR &&
464 val & BMCR_RESET) 479 val & BMCR_RESET)
465 return phy_init_hw(phydev); 480 return phy_init_hw(phydev);
466 481