Messages in this thread Patch in this message | | | Date | Wed, 20 Jul 2022 19:32:41 +0100 | From | "Russell King (Oracle)" <> | Subject | Re: [PATCH v2 07/11] net: phylink: Adjust link settings based on rate adaptation |
| |
On Wed, Jul 20, 2022 at 07:50:52AM +0100, Russell King (Oracle) wrote: > We can do that by storing the PHY rate adaption state, and processing > that in phylink_link_up().
Something like this? I haven't included the IPG (open loop) stuff in this - I think when we come to implement that, we need a new mac method to call to set the IPG just before calling mac_link_up(). Something like:
void mac_set_ipg(struct phylink_config *config, int packet_speed, int interface_speed);
Note that we also have PCS that do rate adaption too, and I think fitting those in with the code below may be easier than storing the media and phy interface speed/duplex separately.
A few further question though - does rate adaption make sense with interface modes that can already natively handle the different speeds, such as SGMII, RGMII, USXGMII, etc?
drivers/net/phy/phylink.c | 103 ++++++++++++++++++++++++++++++++++++++++++++-- include/linux/phylink.h | 1 + 2 files changed, 100 insertions(+), 4 deletions(-)
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 9bd69328dc4d..c89eb74458cd 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -994,23 +994,105 @@ static const char *phylink_pause_to_str(int pause) } } +static int phylink_interface_max_speed(phy_interface_t interface) +{ + switch (interface) { + case PHY_INTERFACE_MODE_100BASEX: + case PHY_INTERFACE_MODE_REVRMII: + case PHY_INTERFACE_MODE_RMII: + case PHY_INTERFACE_MODE_SMII: + case PHY_INTERFACE_MODE_REVMII: + case PHY_INTERFACE_MODE_MII: + return SPEED_100; + + case PHY_INTERFACE_MODE_TBI: + case PHY_INTERFACE_MODE_MOCA: + case PHY_INTERFACE_MODE_RTBI: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_1000BASEKX: + case PHY_INTERFACE_MODE_TRGMII: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_QSGMII: + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_GMII: + return SPEED_1000; + + case PHY_INTERFACE_MODE_2500BASEX: + return SPEED_2500; + + case PHY_INTERFACE_MODE_5GBASER: + return SPEED_5000; + + case PHY_INTERFACE_MODE_XGMII: + case PHY_INTERFACE_MODE_RXAUI: + case PHY_INTERFACE_MODE_XAUI: + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_10GKR: + case PHY_INTERFACE_MODE_USXGMII: + return SPEED_10000; + + case PHY_INTERFACE_MODE_25GBASER: + return SPEED_25000; + + case PHY_INTERFACE_MODE_XLGMII: + return SPEED_40000; + + case PHY_INTERFACE_MODE_INTERNAL: + /* Rate adaption is probably not supported */ + return 0; + + case PHY_INTERFACE_MODE_NA: + case PHY_INTERFACE_MODE_MAX: + return SPEED_UNKNOWN; + } +} + static void phylink_link_up(struct phylink *pl, struct phylink_link_state link_state) { struct net_device *ndev = pl->netdev; + int speed, duplex; + bool rx_pause; + + speed = link_state.speed; + duplex = link_state.duplex; + rx_pause = !!(link_state.pause & MLO_PAUSE_RX); + + switch (state->rate_adaption) { + case RATE_ADAPT_PAUSE: + /* The PHY is doing rate adaption from the media rate (in + * the link_state) to the interface speed, and will send + * pause frames to the MAC to limit its transmission speed. + */ + speed = phylink_interface_max_speed(link_state.interface); + duplex = DUPLEX_FULL; + rx_pause = true; + break; + + case RATE_ADAPT_CRS: + /* The PHY is doing rate adaption from the media rate (in + * the link_state) to the interface speed, and will cause + * collisions to the MAC to limit its transmission speed. + */ + speed = phylink_interface_max_speed(link_state.interface); + duplex = DUPLEX_HALF; + break; + } pl->cur_interface = link_state.interface; if (pl->pcs && pl->pcs->ops->pcs_link_up) pl->pcs->ops->pcs_link_up(pl->pcs, pl->cur_link_an_mode, - pl->cur_interface, - link_state.speed, link_state.duplex); + pl->cur_interface, speed, duplex); pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode, pl->cur_interface, - link_state.speed, link_state.duplex, + speed, duplex, !!(link_state.pause & MLO_PAUSE_TX), - !!(link_state.pause & MLO_PAUSE_RX)); + rx_pause); if (ndev) netif_carrier_on(ndev); @@ -1102,6 +1184,17 @@ static void phylink_resolve(struct work_struct *w) } link_state.interface = pl->phy_state.interface; + /* If we are doing rate adaption, then the + * media speed/duplex has to come from the PHY. + */ + if (pl->phy_state.rate_adaption) { + link_state.rate_adaption = + pl->phy_state.rate_adaption; + link_state.speed = pl->phy_state.speed; + link_state.duplex = + pl->phy_state.duplex; + } + /* If we have a PHY, we need to update with * the PHY flow control bits. */ @@ -1337,6 +1430,7 @@ static void phylink_phy_change(struct phy_device *phydev, bool up) pl->phy_state.speed = phydev->speed; pl->phy_state.duplex = phydev->duplex; pl->phy_state.pause = MLO_PAUSE_NONE; + pl->phy_state.rate_adaption = phydev->rate_adaption; if (tx_pause) pl->phy_state.pause |= MLO_PAUSE_TX; if (rx_pause) @@ -1414,6 +1508,7 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy, pl->phy_state.pause = MLO_PAUSE_NONE; pl->phy_state.speed = SPEED_UNKNOWN; pl->phy_state.duplex = DUPLEX_UNKNOWN; + pl->phy_state.rate_adaption = RATE_ADAPT_NONE; linkmode_copy(pl->supported, supported); linkmode_copy(pl->link_config.advertising, config.advertising); diff --git a/include/linux/phylink.h b/include/linux/phylink.h index 6d06896fc20d..65301e7961b0 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -70,6 +70,7 @@ struct phylink_link_state { int speed; int duplex; int pause; + int rate_adaption; unsigned int link:1; unsigned int an_enabled:1; unsigned int an_complete:1; -- RMK's Patch system: https://www.armlinux.org.uk/developer/patches/ FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
| |