Re: [PATCH 07/14] net: axienet: Fix SGMII support

From: Russell King - ARM Linux admin
Date: Sat Jan 18 2020 - 06:23:52 EST


On Fri, Jan 10, 2020 at 05:04:57PM +0000, Russell King - ARM Linux admin wrote:
> Maybe something like the below will help?
>
> Basically, use phylink_mii_pcs_get_state() instead of
> axienet_mac_pcs_get_state(), and setup lp->phylink_config.pcs_mii
> to point at the MII bus, and lp->phylink_config.pcs_mii_addr to
> access the internal PHY (as per C_PHYADDR parameter.)
>
> You may have some fuzz (with gnu patch) while trying to apply this,
> as you won't have the context for the first and last hunks in this
> patch.
>
> This will probably not be the final version of the patch anyway;
> there's some possibility to pull some of the functionality out of
> phylib into a more general library which would avoid some of the
> functional duplication.

Hi Andre,

Did you have a chance to see whether this helps?

Russell.

>
> diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
> index 75a74a16dc3d..44198fdb3c01 100644
> --- a/drivers/net/phy/phylink.c
> +++ b/drivers/net/phy/phylink.c
> @@ -2073,4 +2073,105 @@ phy_interface_t phylink_select_serdes_interface(unsigned long *interfaces,
> }
> EXPORT_SYMBOL_GPL(phylink_select_serdes_interface);
>
> +static void phylink_decode_advertisement(struct phylink_link_state *state)
> +{
> + __ETHTOOL_DECLARE_LINK_MODE_MASK(u);
> +
> + linkmode_and(u, state->lp_advertising, state->advertising);
> +
> + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, u)) {
> + state->pause = MLO_PAUSE_RX | MLO_PAUSE_TX;
> + } else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, u)) {
> + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
> + state->lp_advertising))
> + state->pause |= MLO_PAUSE_TX;
> + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
> + state->advertising))
> + state->pause |= MLO_PAUSE_RX;
> + }
> +
> + if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, u)) {
> + state->speed = SPEED_2500;
> + state->duplex = DUPLEX_FULL;
> + } else if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, u)) {
> + state->pause = SPEED_1000;
> + state->duplex = DUPLEX_FULL;
> + } else {
> + state->link = false;
> + }
> +}
> +
> +void phylink_mii_pcs_get_state(struct phylink_config *config,
> + struct phylink_link_state *state)
> +{
> + struct mii_bus *bus = config->pcs_mii;
> + int addr = config->pcs_mii_addr;
> + int bmsr, lpa;
> +
> + bmsr = mdiobus_read(bus, addr, MII_BMSR);
> + lpa = mdiobus_read(bus, addr, MII_LPA);
> + if (bmsr < 0 || lpa < 0) {
> + state->link = false;
> + return;
> + }
> +
> + state->link = !!(bmsr & BMSR_LSTATUS);
> + state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE);
> +
> + switch (state->interface) {
> + case PHY_INTERFACE_MODE_1000BASEX:
> + if (lpa & LPA_1000XFULL)
> + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
> + state->lp_advertising);
> + goto lpa_8023z;
> +
> + case PHY_INTERFACE_MODE_2500BASEX:
> + if (lpa & LPA_1000XFULL)
> + linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
> + state->lp_advertising);
> + lpa_8023z:
> + if (lpa & LPA_1000XPAUSE)
> + linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
> + state->lp_advertising);
> + if (lpa & LPA_1000XPAUSE_ASYM)
> + linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
> + state->lp_advertising);
> + if (lpa & LPA_LPACK)
> + linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
> + state->lp_advertising);
> + phylink_decode_advertisement(state);
> + break;
> +
> + case PHY_INTERFACE_MODE_SGMII:
> + switch (lpa & 0x8c00) {
> + case 0x8000:
> + state->speed = SPEED_10;
> + break;
> + case 0x8400:
> + state->speed = SPEED_100;
> + break;
> + case 0x8800:
> + state->speed = SPEED_1000;
> + break;
> + default:
> + state->link = false;
> + break;
> + }
> + switch (lpa & 0x9000) {
> + case 0x9000:
> + state->duplex = DUPLEX_FULL;
> + break;
> + case 0x8000:
> + state->duplex = DUPLEX_HALF;
> + break;
> + }
> + break;
> +
> + default:
> + state->link = false;
> + break;
> + }
> +}
> +EXPORT_SYMBOL_GPL(phylink_mii_pcs_get_state);
> +
> MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/phylink.h b/include/linux/phylink.h
> index 4ea76e083847..cf0fa39b4b21 100644
> --- a/include/linux/phylink.h
> +++ b/include/linux/phylink.h
> @@ -65,6 +65,9 @@ enum phylink_op_type {
> struct phylink_config {
> struct device *dev;
> enum phylink_op_type type;
> +
> + struct mii_bus *pcs_mii;
> + int pcs_mii_addr;
> };
>
> /**
> @@ -292,4 +295,7 @@ phy_interface_t phylink_select_serdes_interface(unsigned long *interfaces,
> const phy_interface_t *pref,
> size_t nprefs);
>
> +void phylink_mii_pcs_get_state(struct phylink_config *config,
> + struct phylink_link_state *state);
> +
> #endif
>
> --
> RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
> FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
> According to speedtest.net: 11.9Mbps down 500kbps up
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@xxxxxxxxxxxxxxxxxxx
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up