--- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -584,10 +584,37 @@ int phylink_speed_up(struct phylink *pl) #define phylink_test(bm, mode) __phylink_do_bit(test_bit, bm, mode) void phylink_set_port_modes(unsigned long *bits); + +/** + * phylink_get_link_timer_ns - return the PCS link timer value + * @interface: link &typedef phy_interface_t mode + * + * Return the PCS link timer setting in nanoseconds for the PHY @interface + * mode, or -EINVAL if not appropriate. + */ +static inline int phylink_get_link_timer_ns(phy_interface_t interface) +{ + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: + return 1600000; + + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + return 10000000; + + default: + return -EINVAL; + } +} + void phylink_helper_basex_speed(struct phylink_link_state *state); +void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state, + u16 bmsr, u16 lpa); void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, struct phylink_link_state *state); +int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface, + const unsigned long *advertising); int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs, phy_interface_t interface, const unsigned long *advertising); --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -885,7 +885,6 @@ static int phylink_change_inband_advert( return 0; } - static void phylink_mac_pcs_get_state(struct phylink *pl, struct phylink_link_state *state) { @@ -2966,6 +2965,52 @@ void phylink_mii_c22_pcs_get_state(struc EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state); /** + * phylink_mii_c22_pcs_decode_state() - Decode MAC PCS state from MII registers + * @state: a pointer to a &struct phylink_link_state. + * @bmsr: The value of the %MII_BMSR register + * @lpa: The value of the %MII_LPA register + * + * Helper for MAC PCS supporting the 802.3 clause 22 register set for + * clause 37 negotiation and/or SGMII control. + * + * Parse the Clause 37 or Cisco SGMII link partner negotiation word into + * the phylink @state structure. This is suitable to be used for implementing + * the mac_pcs_get_state() member of the struct phylink_mac_ops structure if + * 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) +{ + 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 || !state->an_enabled) + return; + + switch (state->interface) { + case PHY_INTERFACE_MODE_1000BASEX: + phylink_decode_c37_word(state, lpa, SPEED_1000); + break; + + case PHY_INTERFACE_MODE_2500BASEX: + phylink_decode_c37_word(state, lpa, SPEED_2500); + break; + + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + phylink_decode_sgmii_word(state, lpa); + break; + + default: + state->link = false; + break; + } +} +EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_decode_state); + +/** * phylink_mii_c22_pcs_set_advertisement() - configure the clause 37 PCS * advertisement * @pcs: a pointer to a &struct mdio_device. @@ -3037,6 +3082,46 @@ int phylink_mii_c22_pcs_set_advertisemen EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_set_advertisement); /** + * phylink_mii_c22_pcs_encode_advertisement() - configure the clause 37 PCS + * advertisement + * @interface: the PHY interface mode being configured + * @advertising: the ethtool advertisement mask + * + * Helper for MAC PCS supporting the 802.3 clause 22 register set for + * clause 37 negotiation and/or SGMII control. + * + * Encode the clause 37 PCS advertisement as specified by @interface and + * @advertising. + * + * Return: The new value for @adv, or ``-EINVAL`` if it should not be changed. + */ +int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface, + const unsigned long *advertising) +{ + u16 adv; + + switch (interface) { + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + adv = ADVERTISE_1000XFULL; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, + advertising)) + adv |= ADVERTISE_1000XPAUSE; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, + advertising)) + adv |= ADVERTISE_1000XPSE_ASYM; + return adv; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + return 0x0001; + default: + /* Nothing to do for other modes */ + return -EINVAL; + } +} +EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_encode_advertisement); + +/** * phylink_mii_c22_pcs_config() - configure clause 22 PCS * @pcs: a pointer to a &struct mdio_device. * @mode: link autonegotiation mode