Report the link, speed and duplex for SGMII links, read from the SGMII, RGMII and SMII status and control register. Signed-off-by: Russell King (Oracle) --- rfc->v1: fix setting SGMII's link status - depend on both link status. --- .../net/ethernet/stmicro/stmmac/stmmac_pcs.c | 46 ++++++++++++++++++- .../net/ethernet/stmicro/stmmac/stmmac_pcs.h | 4 ++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c index 73fc56ce5e55..9dd7e78cfbc4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c @@ -17,6 +17,16 @@ #define GMAC_ANE_LPA 0x0c /* ANE link partener ability */ #define GMAC_TBI 0x14 /* TBI extend status */ +/* + * RGSMII status bitfield definitions. + */ +#define GMAC_RGSMIII_LNKMOD BIT(0) +#define GMAC_RGSMIII_SPEED_MASK GENMASK(2, 1) +#define GMAC_RGSMIII_SPEED_125 2 +#define GMAC_RGSMIII_SPEED_25 1 +#define GMAC_RGSMIII_SPEED_2_5 0 +#define GMAC_RGSMIII_LNKSTS BIT(3) + static enum ethtool_link_mode_bit_indices dwmac_hd_mode_bits[] = { ETHTOOL_LINK_MODE_10baseT_Half_BIT, ETHTOOL_LINK_MODE_100baseT_Half_BIT, @@ -97,7 +107,7 @@ static void dwmac_integrated_pcs_get_state(struct phylink_pcs *pcs, struct phylink_link_state *state) { struct stmmac_pcs *spcs = phylink_pcs_to_stmmac_pcs(pcs); - u32 status, lpa; + u32 status, lpa, rgsmii; status = readl(spcs->base + GMAC_AN_STATUS); @@ -111,7 +121,37 @@ static void dwmac_integrated_pcs_get_state(struct phylink_pcs *pcs, phylink_mii_c22_pcs_decode_state(state, neg_mode, status, lpa); } else { - state->link = false; + rgsmii = field_get(spcs->rgsmii_status_mask, + readl(spcs->rgsmii)); + + state->link = status & BMSR_LSTATUS && + rgsmii & GMAC_RGSMIII_LNKSTS; + + if (state->link && neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { + /* FIXME: fill in speed and duplex. This requires the + * contents of the dwmac1000 GMAC_RGSMIIIS or dwmac4 + * GMAC_PHYIF_CONTROL_STATUS register. + */ + state->duplex = rgsmii & GMAC_RGSMIII_LNKMOD ? + DUPLEX_FULL : DUPLEX_HALF; + switch (FIELD_GET(GMAC_RGSMIII_SPEED_MASK, rgsmii)) { + case GMAC_RGSMIII_SPEED_2_5: + state->speed = SPEED_10; + break; + + case GMAC_RGSMIII_SPEED_25: + state->speed = SPEED_100; + break; + + case GMAC_RGSMIII_SPEED_125: + state->speed = SPEED_1000; + break; + + default: + state->link = false; + break; + } + } } } @@ -205,6 +245,8 @@ int stmmac_integrated_pcs_init(struct stmmac_priv *priv, spcs->priv = priv; spcs->base = priv->ioaddr + pcs_info->pcs_offset; + spcs->rgsmii = priv->ioaddr + pcs_info->rgsmii_offset; + spcs->rgsmii_status_mask = pcs_info->rgsmii_status_mask; spcs->int_mask = pcs_info->int_mask; spcs->pcs.ops = &dwmac_integrated_pcs_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h index a7c71f40f952..f9e7a7ed840b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h @@ -29,12 +29,16 @@ struct stmmac_priv; struct stmmac_pcs_info { unsigned int pcs_offset; + unsigned int rgsmii_offset; + u32 rgsmii_status_mask; u32 int_mask; }; struct stmmac_pcs { struct stmmac_priv *priv; void __iomem *base; + void __iomem *rgsmii; + u32 rgsmii_status_mask; u32 int_mask; phy_interface_t interface; struct phylink_pcs pcs; -- 2.47.3