diff options
author | Russell King <rmk+kernel@armlinux.org.uk> | 2019-05-28 05:57:29 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-05-31 15:37:46 -0400 |
commit | cdea04c24616416f8239d86a1012d924fb6f0d30 (patch) | |
tree | 76eaf93f06441081b2b74d70c9d4198b7460f56d /drivers/net/phy/phy.c | |
parent | 7b3b0e89bcf3acb56bf59666122226de0913a8b4 (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.c | 33 |
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 | ||