From cdd74a824c3c5aa90d1674d4b39b1029a5d02e7c Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 4 Jan 2020 00:41:35 +0000 Subject: net: phy: marvell*: add support for hw resolved pause modes Support reporting the hardware resolved pause enablement states via phylib, overriding our software implementation. Signed-off-by: Russell King --- drivers/net/phy/marvell.c | 41 +++++++++++++++++++++++++++++++++++++++-- drivers/net/phy/marvell10g.c | 6 ++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 620052c023a5..0213e07724be 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -158,6 +158,10 @@ #define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000 #define MII_M1011_PHY_STATUS_RESOLVED 0x0800 #define MII_M1011_PHY_STATUS_LINK 0x0400 +#define MII_M1111_PHY_STATUS_TX_PAUSE 0x0008 +#define MII_M1111_PHY_STATUS_RX_PAUSE 0x0004 +#define MII_88E151X_PHY_STATUS_TX_PAUSE 0x0200 +#define MII_88E151X_PHY_STATUS_RX_PAUSE 0x0100 #define MII_88E3016_PHY_SPEC_CTRL 0x10 #define MII_88E3016_DISABLE_SCRAMBLER 0x0200 @@ -283,6 +287,8 @@ struct marvell_priv { u32 last; u32 step; s8 pair; + u16 tx_pause_mask; + u16 rx_pause_mask; }; static int marvell_read_page(struct phy_device *phydev) @@ -1455,6 +1461,7 @@ static void fiber_lpa_mod_linkmode_lpa_t(unsigned long *advertising, u32 lpa) static int marvell_read_status_page_an(struct phy_device *phydev, int fiber, int status) { + struct marvell_priv *priv = phydev->priv; int lpa; int err; @@ -1510,6 +1517,11 @@ static int marvell_read_status_page_an(struct phy_device *phydev, } } + phydev->resolved_tx_pause = !!(status & priv->tx_pause_mask); + phydev->resolved_rx_pause = !!(status & priv->rx_pause_mask); + phydev->resolved_pause_valid = !fiber && priv->tx_pause_mask && + priv->rx_pause_mask; + return 0; } @@ -1552,6 +1564,7 @@ static int marvell_read_status_page(struct phy_device *phydev, int page) phydev->asym_pause = 0; phydev->speed = SPEED_UNKNOWN; phydev->duplex = DUPLEX_UNKNOWN; + phydev->resolved_pause_valid = false; if (phydev->autoneg == AUTONEG_ENABLE) err = marvell_read_status_page_an(phydev, fiber, status); @@ -2670,6 +2683,23 @@ static int marvell_probe(struct phy_device *phydev) return 0; } +static int marvell_probe_pause(struct phy_device *phydev, u16 tx_pause_mask, + u16 rx_pause_mask) +{ + struct marvell_priv *priv; + int err; + + err = marvell_probe(phydev); + if (err) + return err; + + priv = phydev->priv; + priv->tx_pause_mask = tx_pause_mask; + priv->rx_pause_mask = rx_pause_mask; + + return 0; +} + static int m88e1121_probe(struct phy_device *phydev) { int err; @@ -2681,11 +2711,18 @@ static int m88e1121_probe(struct phy_device *phydev) return m88e1121_hwmon_probe(phydev); } +static int m88e1111_probe(struct phy_device *phydev) +{ + return marvell_probe_pause(phydev, MII_M1111_PHY_STATUS_TX_PAUSE, + MII_M1111_PHY_STATUS_RX_PAUSE); +} + static int m88e1510_probe(struct phy_device *phydev) { int err; - err = marvell_probe(phydev); + err = marvell_probe_pause(phydev, MII_88E151X_PHY_STATUS_TX_PAUSE, + MII_88E151X_PHY_STATUS_RX_PAUSE); if (err) return err; @@ -2747,7 +2784,7 @@ static struct phy_driver marvell_drivers[] = { .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1111", /* PHY_GBIT_FEATURES */ - .probe = marvell_probe, + .probe = m88e1111_probe, .config_init = m88e1111_config_init, .config_aneg = m88e1111_config_aneg, .read_status = marvell_read_status, diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index 5ccbf2e055d8..246cb7daeca5 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -73,6 +73,8 @@ enum { MV_PCS_CSSR1_SPD1_10 = 0x0000, MV_PCS_CSSR1_DUPLEX_FULL= BIT(13), MV_PCS_CSSR1_RESOLVED = BIT(11), + MV_PCS_CSSR1_TX_PAUSE = BIT(9), + MV_PCS_CSSR1_RX_PAUSE = BIT(8), MV_PCS_CSSR1_MDIX = BIT(6), MV_PCS_CSSR1_SPD2_MASK = 0x000c, MV_PCS_CSSR1_SPD2_5000 = 0x0008, @@ -823,6 +825,10 @@ static int mv3310_read_status_copper(struct phy_device *phydev) phydev->mdix = cssr1 & MV_PCS_CSSR1_MDIX ? ETH_TP_MDI_X : ETH_TP_MDI; + phydev->resolved_tx_pause = !!(cssr1 & MV_PCS_CSSR1_TX_PAUSE); + phydev->resolved_rx_pause = !!(cssr1 & MV_PCS_CSSR1_RX_PAUSE); + phydev->resolved_pause_valid = true; + if (val & MDIO_AN_STAT1_COMPLETE) { val = genphy_c45_read_lpa(phydev); if (val < 0) -- cgit