net: phy: marvell10g: add MDI swap reporting
authorRussell King <rmk+kernel@armlinux.org.uk>
Fri, 29 Dec 2017 12:46:27 +0000 (12:46 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 2 Jan 2018 20:00:49 +0000 (15:00 -0500)
Add reporting of the MDI swap to the Marvell 10G PHY driver by providing
a generic implementation for the standard 10GBASE-T pair swap register
and polarity register.  We also support reading the MDI swap status for
1G and below from a PCS register.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/marvell10g.c
drivers/net/phy/phy-c45.c
include/linux/phy.h

index 37ba68d7c3852d34ba72ed0fc1668846eaa9c54d..bf1a218415be80fd466eeb916309882c4f980d58 100644 (file)
@@ -29,6 +29,11 @@ enum {
        MV_PCS_BASE_R           = 0x1000,
        MV_PCS_1000BASEX        = 0x2000,
 
+       MV_PCS_PAIRSWAP         = 0x8182,
+       MV_PCS_PAIRSWAP_MASK    = 0x0003,
+       MV_PCS_PAIRSWAP_AB      = 0x0002,
+       MV_PCS_PAIRSWAP_NONE    = 0x0003,
+
        /* These registers appear at 0x800X and 0xa00X - the 0xa00X control
         * registers appear to set themselves to the 0x800X when AN is
         * restarted, but status registers appear readable from either.
@@ -180,6 +185,9 @@ static int mv3310_config_aneg(struct phy_device *phydev)
        u32 advertising;
        int ret;
 
+       /* We don't support manual MDI control */
+       phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
+
        if (phydev->autoneg == AUTONEG_DISABLE) {
                ret = genphy_c45_pma_setup_forced(phydev);
                if (ret < 0)
@@ -269,6 +277,7 @@ static int mv3310_read_status(struct phy_device *phydev)
        phydev->link = 0;
        phydev->pause = 0;
        phydev->asym_pause = 0;
+       phydev->mdix = 0;
 
        val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1);
        if (val < 0)
@@ -323,6 +332,28 @@ static int mv3310_read_status(struct phy_device *phydev)
                        return val;
        }
 
+       if (phydev->speed == SPEED_10000) {
+               val = genphy_c45_read_mdix(phydev);
+               if (val < 0)
+                       return val;
+       } else {
+               val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_PAIRSWAP);
+               if (val < 0)
+                       return val;
+
+               switch (val & MV_PCS_PAIRSWAP_MASK) {
+               case MV_PCS_PAIRSWAP_AB:
+                       phydev->mdix = ETH_TP_MDI_X;
+                       break;
+               case MV_PCS_PAIRSWAP_NONE:
+                       phydev->mdix = ETH_TP_MDI;
+                       break;
+               default:
+                       phydev->mdix = ETH_TP_MDI_INVALID;
+                       break;
+               }
+       }
+
        if ((phydev->interface == PHY_INTERFACE_MODE_SGMII ||
             phydev->interface == PHY_INTERFACE_MODE_10GKR) && phydev->link) {
                /* The PHY automatically switches its serdes interface (and
index dada819c6b78cdaec225f841189f39153bd55bf3..a4576859afae429c8d7ac9955459c3f187bd35dd 100644 (file)
@@ -233,6 +233,39 @@ int genphy_c45_read_pma(struct phy_device *phydev)
 }
 EXPORT_SYMBOL_GPL(genphy_c45_read_pma);
 
+/**
+ * genphy_c45_read_mdix - read mdix status from PMA
+ * @phydev: target phy_device struct
+ */
+int genphy_c45_read_mdix(struct phy_device *phydev)
+{
+       int val;
+
+       if (phydev->speed == SPEED_10000) {
+               val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
+                                  MDIO_PMA_10GBT_SWAPPOL);
+               if (val < 0)
+                       return val;
+
+               switch (val) {
+               case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX:
+                       phydev->mdix = ETH_TP_MDI;
+                       break;
+
+               case 0:
+                       phydev->mdix = ETH_TP_MDI_X;
+                       break;
+
+               default:
+                       phydev->mdix = ETH_TP_MDI_INVALID;
+                       break;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(genphy_c45_read_mdix);
+
 /* The gen10g_* functions are the old Clause 45 stub */
 
 static int gen10g_config_aneg(struct phy_device *phydev)
index c4b4715caa2139d64301a1864b67c7bf034323a5..bc379a408c4ffea000a57148731344393a13dd69 100644 (file)
@@ -901,6 +901,7 @@ int genphy_c45_read_lpa(struct phy_device *phydev);
 int genphy_c45_read_pma(struct phy_device *phydev);
 int genphy_c45_pma_setup_forced(struct phy_device *phydev);
 int genphy_c45_an_disable_aneg(struct phy_device *phydev);
+int genphy_c45_read_mdix(struct phy_device *phydev);
 
 static inline int phy_read_status(struct phy_device *phydev)
 {