diff options
Diffstat (limited to 'drivers/net/phy/phylink.c')
| -rw-r--r-- | drivers/net/phy/phylink.c | 60 |
1 files changed, 43 insertions, 17 deletions
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 31754d5fd659..ff0efb52189f 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1492,12 +1492,24 @@ static int phylink_change_inband_advert(struct phylink *pl) static void phylink_mac_pcs_get_state(struct phylink *pl, struct phylink_link_state *state) { + struct phylink_pcs *pcs; + bool autoneg; + linkmode_copy(state->advertising, pl->link_config.advertising); linkmode_zero(state->lp_advertising); state->interface = pl->link_config.interface; state->rate_matching = pl->link_config.rate_matching; - if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, - state->advertising)) { + state->an_complete = 0; + state->link = 1; + + pcs = pl->pcs; + if (!pcs || pcs->neg_mode) + autoneg = pl->pcs_neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED; + else + autoneg = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + state->advertising); + + if (autoneg) { state->speed = SPEED_UNKNOWN; state->duplex = DUPLEX_UNKNOWN; state->pause = MLO_PAUSE_NONE; @@ -1506,11 +1518,9 @@ static void phylink_mac_pcs_get_state(struct phylink *pl, state->duplex = pl->link_config.duplex; state->pause = pl->link_config.pause; } - state->an_complete = 0; - state->link = 1; - if (pl->pcs) - pl->pcs->ops->pcs_get_state(pl->pcs, state); + if (pcs) + pcs->ops->pcs_get_state(pcs, pl->pcs_neg_mode, state); else state->link = 0; } @@ -3850,6 +3860,7 @@ static void phylink_decode_usgmii_word(struct phylink_link_state *state, /** * phylink_mii_c22_pcs_decode_state() - Decode MAC PCS state from MII registers * @state: a pointer to a &struct phylink_link_state. + * @neg_mode: link negotiation mode (PHYLINK_PCS_NEG_xxx) * @bmsr: The value of the %MII_BMSR register * @lpa: The value of the %MII_LPA register * @@ -3862,32 +3873,45 @@ static void phylink_decode_usgmii_word(struct phylink_link_state *state, * accessing @bmsr and @lpa cannot be done with MDIO directly. */ void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state, - u16 bmsr, u16 lpa) + unsigned int neg_mode, u16 bmsr, u16 lpa) { state->link = !!(bmsr & BMSR_LSTATUS); state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); - /* If there is no link or autonegotiation is disabled, the LP advertisement - * data is not meaningful, so don't go any further. - */ - if (!state->link || !linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, - state->advertising)) + + /* If the link is down, the advertisement data is undefined. */ + if (!state->link) return; switch (state->interface) { case PHY_INTERFACE_MODE_1000BASEX: - phylink_decode_c37_word(state, lpa, SPEED_1000); + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { + phylink_decode_c37_word(state, lpa, SPEED_1000); + } else { + state->speed = SPEED_1000; + state->duplex = DUPLEX_FULL; + state->pause |= MLO_PAUSE_TX | MLO_PAUSE_RX; + } break; case PHY_INTERFACE_MODE_2500BASEX: - phylink_decode_c37_word(state, lpa, SPEED_2500); + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { + phylink_decode_c37_word(state, lpa, SPEED_2500); + } else { + state->speed = SPEED_2500; + state->duplex = DUPLEX_FULL; + state->pause |= MLO_PAUSE_TX | MLO_PAUSE_RX; + } break; case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_QSGMII: - phylink_decode_sgmii_word(state, lpa); + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) + phylink_decode_sgmii_word(state, lpa); break; + case PHY_INTERFACE_MODE_QUSGMII: - phylink_decode_usgmii_word(state, lpa); + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) + phylink_decode_usgmii_word(state, lpa); break; default: @@ -3900,6 +3924,7 @@ EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_decode_state); /** * phylink_mii_c22_pcs_get_state() - read the MAC PCS state * @pcs: a pointer to a &struct mdio_device. + * @neg_mode: link negotiation mode (PHYLINK_PCS_NEG_xxx) * @state: a pointer to a &struct phylink_link_state. * * Helper for MAC PCS supporting the 802.3 clause 22 register set for @@ -3912,6 +3937,7 @@ EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_decode_state); * structure. */ void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, + unsigned int neg_mode, struct phylink_link_state *state) { int bmsr, lpa; @@ -3923,7 +3949,7 @@ void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, return; } - phylink_mii_c22_pcs_decode_state(state, bmsr, lpa); + phylink_mii_c22_pcs_decode_state(state, neg_mode, bmsr, lpa); } EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state); |
