|
@@ -0,0 +1,148 @@
|
|
|
+From 3c42563b30417afc8855a3b4c1b38c2f36f78657 Mon Sep 17 00:00:00 2001
|
|
|
+From: Sean Anderson <[email protected]>
|
|
|
+Date: Tue, 20 Sep 2022 18:12:35 -0400
|
|
|
+Subject: [PATCH] net: phy: aquantia: Add support for rate matching
|
|
|
+
|
|
|
+This adds support for rate matching for phys similar to the AQR107. We
|
|
|
+assume that all phys using aqr107_read_status support rate matching.
|
|
|
+However, it could be possible to determine support based on the firmware
|
|
|
+revision if there are phys discovered which do not support rate
|
|
|
+matching. However, as rate matching is advertised in the datasheets for
|
|
|
+these phys, I suspect it is supported most boards.
|
|
|
+
|
|
|
+Despite the name, the "config" registers are updated with the current
|
|
|
+rate matching method (if any). Because they appear to be updated
|
|
|
+automatically, I don't know if these registers can be used to disable
|
|
|
+rate matching.
|
|
|
+
|
|
|
+Signed-off-by: Sean Anderson <[email protected]>
|
|
|
+Signed-off-by: David S. Miller <[email protected]>
|
|
|
+---
|
|
|
+ drivers/net/phy/aquantia_main.c | 51 ++++++++++++++++++++++++++++++---
|
|
|
+ 1 file changed, 47 insertions(+), 4 deletions(-)
|
|
|
+
|
|
|
+--- a/drivers/net/phy/aquantia_main.c
|
|
|
++++ b/drivers/net/phy/aquantia_main.c
|
|
|
+@@ -97,6 +97,19 @@
|
|
|
+ #define VEND1_GLOBAL_GEN_STAT2 0xc831
|
|
|
+ #define VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG BIT(15)
|
|
|
+
|
|
|
++/* The following registers all have similar layouts; first the registers... */
|
|
|
++#define VEND1_GLOBAL_CFG_10M 0x0310
|
|
|
++#define VEND1_GLOBAL_CFG_100M 0x031b
|
|
|
++#define VEND1_GLOBAL_CFG_1G 0x031c
|
|
|
++#define VEND1_GLOBAL_CFG_2_5G 0x031d
|
|
|
++#define VEND1_GLOBAL_CFG_5G 0x031e
|
|
|
++#define VEND1_GLOBAL_CFG_10G 0x031f
|
|
|
++/* ...and now the fields */
|
|
|
++#define VEND1_GLOBAL_CFG_RATE_ADAPT GENMASK(8, 7)
|
|
|
++#define VEND1_GLOBAL_CFG_RATE_ADAPT_NONE 0
|
|
|
++#define VEND1_GLOBAL_CFG_RATE_ADAPT_USX 1
|
|
|
++#define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2
|
|
|
++
|
|
|
+ #define VEND1_GLOBAL_RSVD_STAT1 0xc885
|
|
|
+ #define VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID GENMASK(7, 4)
|
|
|
+ #define VEND1_GLOBAL_RSVD_STAT1_PROV_ID GENMASK(3, 0)
|
|
|
+@@ -347,40 +360,57 @@ static int aqr_read_status(struct phy_de
|
|
|
+
|
|
|
+ static int aqr107_read_rate(struct phy_device *phydev)
|
|
|
+ {
|
|
|
++ u32 config_reg;
|
|
|
+ int val;
|
|
|
+
|
|
|
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1);
|
|
|
+ if (val < 0)
|
|
|
+ return val;
|
|
|
+
|
|
|
++ if (val & MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX)
|
|
|
++ phydev->duplex = DUPLEX_FULL;
|
|
|
++ else
|
|
|
++ phydev->duplex = DUPLEX_HALF;
|
|
|
++
|
|
|
+ switch (FIELD_GET(MDIO_AN_TX_VEND_STATUS1_RATE_MASK, val)) {
|
|
|
+ case MDIO_AN_TX_VEND_STATUS1_10BASET:
|
|
|
+ phydev->speed = SPEED_10;
|
|
|
++ config_reg = VEND1_GLOBAL_CFG_10M;
|
|
|
+ break;
|
|
|
+ case MDIO_AN_TX_VEND_STATUS1_100BASETX:
|
|
|
+ phydev->speed = SPEED_100;
|
|
|
++ config_reg = VEND1_GLOBAL_CFG_100M;
|
|
|
+ break;
|
|
|
+ case MDIO_AN_TX_VEND_STATUS1_1000BASET:
|
|
|
+ phydev->speed = SPEED_1000;
|
|
|
++ config_reg = VEND1_GLOBAL_CFG_1G;
|
|
|
+ break;
|
|
|
+ case MDIO_AN_TX_VEND_STATUS1_2500BASET:
|
|
|
+ phydev->speed = SPEED_2500;
|
|
|
++ config_reg = VEND1_GLOBAL_CFG_2_5G;
|
|
|
+ break;
|
|
|
+ case MDIO_AN_TX_VEND_STATUS1_5000BASET:
|
|
|
+ phydev->speed = SPEED_5000;
|
|
|
++ config_reg = VEND1_GLOBAL_CFG_5G;
|
|
|
+ break;
|
|
|
+ case MDIO_AN_TX_VEND_STATUS1_10GBASET:
|
|
|
+ phydev->speed = SPEED_10000;
|
|
|
++ config_reg = VEND1_GLOBAL_CFG_10G;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ phydev->speed = SPEED_UNKNOWN;
|
|
|
+- break;
|
|
|
++ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+- if (val & MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX)
|
|
|
+- phydev->duplex = DUPLEX_FULL;
|
|
|
++ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, config_reg);
|
|
|
++ if (val < 0)
|
|
|
++ return val;
|
|
|
++
|
|
|
++ if (FIELD_GET(VEND1_GLOBAL_CFG_RATE_ADAPT, val) ==
|
|
|
++ VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE)
|
|
|
++ phydev->rate_matching = RATE_MATCH_PAUSE;
|
|
|
+ else
|
|
|
+- phydev->duplex = DUPLEX_HALF;
|
|
|
++ phydev->rate_matching = RATE_MATCH_NONE;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+@@ -647,6 +677,16 @@ static int aqr107_wait_processor_intensi
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
++static int aqr107_get_rate_matching(struct phy_device *phydev,
|
|
|
++ phy_interface_t iface)
|
|
|
++{
|
|
|
++ if (iface == PHY_INTERFACE_MODE_10GBASER ||
|
|
|
++ iface == PHY_INTERFACE_MODE_2500BASEX ||
|
|
|
++ iface == PHY_INTERFACE_MODE_NA)
|
|
|
++ return RATE_MATCH_PAUSE;
|
|
|
++ return RATE_MATCH_NONE;
|
|
|
++}
|
|
|
++
|
|
|
+ static int aqr107_suspend(struct phy_device *phydev)
|
|
|
+ {
|
|
|
+ int err;
|
|
|
+@@ -720,6 +760,7 @@ static struct phy_driver aqr_driver[] =
|
|
|
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR107),
|
|
|
+ .name = "Aquantia AQR107",
|
|
|
+ .probe = aqr107_probe,
|
|
|
++ .get_rate_matching = aqr107_get_rate_matching,
|
|
|
+ .config_init = aqr107_config_init,
|
|
|
+ .config_aneg = aqr_config_aneg,
|
|
|
+ .config_intr = aqr_config_intr,
|
|
|
+@@ -738,6 +779,7 @@ static struct phy_driver aqr_driver[] =
|
|
|
+ PHY_ID_MATCH_MODEL(PHY_ID_AQCS109),
|
|
|
+ .name = "Aquantia AQCS109",
|
|
|
+ .probe = aqr107_probe,
|
|
|
++ .get_rate_matching = aqr107_get_rate_matching,
|
|
|
+ .config_init = aqcs109_config_init,
|
|
|
+ .config_aneg = aqr_config_aneg,
|
|
|
+ .config_intr = aqr_config_intr,
|
|
|
+@@ -764,6 +806,7 @@ static struct phy_driver aqr_driver[] =
|
|
|
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C),
|
|
|
+ .name = "Aquantia AQR113C",
|
|
|
+ .probe = aqr107_probe,
|
|
|
++ .get_rate_matching = aqr107_get_rate_matching,
|
|
|
+ .config_init = aqr107_config_init,
|
|
|
+ .config_aneg = aqr_config_aneg,
|
|
|
+ .config_intr = aqr_config_intr,
|