net: phy: aquantia: check for changed interface mode in read_status
authorNikita Yushchenko <nikita.yoush@cogentembedded.com>
Tue, 19 Mar 2019 22:05:50 +0000 (23:05 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 20 Mar 2019 17:58:17 +0000 (10:58 -0700)
Depending on the auto-negotiated speed the PHY may change the interface
mode. Check for new mode and set phydev->interface accordingly.

Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
[hkallweit1@gmail.com: picked from bigger patch and reworked]
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/aquantia_main.c

index 74c16b85d32de7ce2277f5eebd6b6fc8134c518c..034b82d413eea67e864839ec1a53625002c5f67e 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/bitfield.h>
 #include <linux/phy.h>
 
 #include "aquantia.h"
 #define PHY_ID_AQCS109 0x03a1b5c2
 #define PHY_ID_AQR405  0x03a1b4b0
 
+#define MDIO_PHYXS_VEND_IF_STATUS              0xe812
+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK    GENMASK(7, 3)
+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR      0
+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI     2
+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII   6
+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII 10
+
 #define MDIO_AN_VEND_PROV                      0xc400
 #define MDIO_AN_VEND_PROV_1000BASET_FULL       BIT(15)
 #define MDIO_AN_VEND_PROV_1000BASET_HALF       BIT(14)
@@ -178,6 +186,40 @@ static int aqr_read_status(struct phy_device *phydev)
        return genphy_c45_read_status(phydev);
 }
 
+static int aqr107_read_status(struct phy_device *phydev)
+{
+       int val, ret;
+
+       ret = aqr_read_status(phydev);
+       if (ret)
+               return ret;
+
+       if (!phydev->link)
+               return 0;
+
+       val = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_VEND_IF_STATUS);
+       if (val < 0)
+               return val;
+
+       switch (FIELD_GET(MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK, val)) {
+       case MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR:
+       case MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI:
+               phydev->interface = PHY_INTERFACE_MODE_10GKR;
+               break;
+       case MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII:
+               phydev->interface = PHY_INTERFACE_MODE_SGMII;
+               break;
+       case MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII:
+               phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+               break;
+       default:
+               phydev->interface = PHY_INTERFACE_MODE_NA;
+               break;
+       }
+
+       return 0;
+}
+
 static int aqr107_config_init(struct phy_device *phydev)
 {
        /* Check that the PHY interface type is compatible */
@@ -254,7 +296,7 @@ static struct phy_driver aqr_driver[] = {
        .config_aneg    = aqr_config_aneg,
        .config_intr    = aqr_config_intr,
        .ack_interrupt  = aqr_ack_interrupt,
-       .read_status    = aqr_read_status,
+       .read_status    = aqr107_read_status,
 },
 {
        PHY_ID_MATCH_MODEL(PHY_ID_AQCS109),
@@ -266,7 +308,7 @@ static struct phy_driver aqr_driver[] = {
        .config_aneg    = aqr_config_aneg,
        .config_intr    = aqr_config_intr,
        .ack_interrupt  = aqr_ack_interrupt,
-       .read_status    = aqr_read_status,
+       .read_status    = aqr107_read_status,
 },
 {
        PHY_ID_MATCH_MODEL(PHY_ID_AQR405),