Commit d28b159b authored by David S. Miller's avatar David S. Miller

Merge branch 'stmmac-PCS-modernize'

Russell King says:

====================
net: stmmac/xpcs: modernise PCS support

This series updates xpcs and stmmac for the recent changes to phylink
to better support split PCS and to get rid of private MAC validation
functions.

This series is slightly more involved than other conversions as stmmac
has already had optional proper split PCS support.

The first six patches of this series were originally posted on 16th
December for CFT, and Wong Vee Khee reported his Intel Elkhart Lake
setup was fine the first six these. However, no tested-by was given.

The patches:

1) Provide a function to query the xpcs for the interface modes that
   are supported.

2) Populates the MAC capabilities and switches stmmac_validate() to use
   phylink_get_linkmodes(). We do not use phylink_generic_validate() yet
   as (a) we do not always have the supported interfaces populated, and
   (b) the existing code does not restrict based on interface. There
   should be no functional effect from this patch.

3) Populates phylink's supported interfaces from the xpcs when the xpcs
   is configured by firmware and also the firmware configured interface
   mode. Note: this will restrict stmmac to only supporting these
   interfaces modes - stmmac maintainers need to verify that this
   behaviour is acceptable.

4) stmmac_validate() tail-calls xpcs_validate(), but we don't need it to
   now that PCS have their own validation method. Convert stmmac and
   xpcs to use this method instead.

5) xpcs sets the poll field of phylink_pcs to true, meaning xpcs
   requires its status to be polled. There is no need to also set the
   phylink_config.pcs_poll. Remove this.

6) Switch to phylink_generic_validate(). This is probably the most
   contravertial change in this patch set as this will cause the MAC to
   restrict link modes based on the interface mode. From an inspection
   of the xpcs driver, this should be safe, as XPCS only further
   restricts the link modes to a subset of these (whether that is
   correct or not is not an issue I am addressing here.) For
   implementations that do not use xpcs, this is a more open question
   and needs feedback from stmmac maintainers.

7) Convert to use mac_select_pcs() rather than phylink_set_pcs() to set
   the PCS - the intention is to eventually remove phylink_set_pcs()
   once there are no more users of this.

v2: fix signoff and temporary warning in patch 4
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3cade91d 72e94511
...@@ -936,105 +936,15 @@ static void stmmac_mac_flow_ctrl(struct stmmac_priv *priv, u32 duplex) ...@@ -936,105 +936,15 @@ static void stmmac_mac_flow_ctrl(struct stmmac_priv *priv, u32 duplex)
priv->pause, tx_cnt); priv->pause, tx_cnt);
} }
static void stmmac_validate(struct phylink_config *config, static struct phylink_pcs *stmmac_mac_select_pcs(struct phylink_config *config,
unsigned long *supported, phy_interface_t interface)
struct phylink_link_state *state)
{ {
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
__ETHTOOL_DECLARE_LINK_MODE_MASK(mac_supported) = { 0, };
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
int tx_cnt = priv->plat->tx_queues_to_use;
int max_speed = priv->plat->max_speed;
phylink_set(mac_supported, 10baseT_Half); if (!priv->hw->xpcs)
phylink_set(mac_supported, 10baseT_Full); return NULL;
phylink_set(mac_supported, 100baseT_Half);
phylink_set(mac_supported, 100baseT_Full);
phylink_set(mac_supported, 1000baseT_Half);
phylink_set(mac_supported, 1000baseT_Full);
phylink_set(mac_supported, 1000baseKX_Full);
phylink_set(mac_supported, Autoneg);
phylink_set(mac_supported, Pause);
phylink_set(mac_supported, Asym_Pause);
phylink_set_port_modes(mac_supported);
/* Cut down 1G if asked to */
if ((max_speed > 0) && (max_speed < 1000)) {
phylink_set(mask, 1000baseT_Full);
phylink_set(mask, 1000baseX_Full);
} else if (priv->plat->has_gmac4) {
if (!max_speed || max_speed >= 2500) {
phylink_set(mac_supported, 2500baseT_Full);
phylink_set(mac_supported, 2500baseX_Full);
}
} else if (priv->plat->has_xgmac) {
if (!max_speed || (max_speed >= 2500)) {
phylink_set(mac_supported, 2500baseT_Full);
phylink_set(mac_supported, 2500baseX_Full);
}
if (!max_speed || (max_speed >= 5000)) {
phylink_set(mac_supported, 5000baseT_Full);
}
if (!max_speed || (max_speed >= 10000)) {
phylink_set(mac_supported, 10000baseSR_Full);
phylink_set(mac_supported, 10000baseLR_Full);
phylink_set(mac_supported, 10000baseER_Full);
phylink_set(mac_supported, 10000baseLRM_Full);
phylink_set(mac_supported, 10000baseT_Full);
phylink_set(mac_supported, 10000baseKX4_Full);
phylink_set(mac_supported, 10000baseKR_Full);
}
if (!max_speed || (max_speed >= 25000)) {
phylink_set(mac_supported, 25000baseCR_Full);
phylink_set(mac_supported, 25000baseKR_Full);
phylink_set(mac_supported, 25000baseSR_Full);
}
if (!max_speed || (max_speed >= 40000)) {
phylink_set(mac_supported, 40000baseKR4_Full);
phylink_set(mac_supported, 40000baseCR4_Full);
phylink_set(mac_supported, 40000baseSR4_Full);
phylink_set(mac_supported, 40000baseLR4_Full);
}
if (!max_speed || (max_speed >= 50000)) {
phylink_set(mac_supported, 50000baseCR2_Full);
phylink_set(mac_supported, 50000baseKR2_Full);
phylink_set(mac_supported, 50000baseSR2_Full);
phylink_set(mac_supported, 50000baseKR_Full);
phylink_set(mac_supported, 50000baseSR_Full);
phylink_set(mac_supported, 50000baseCR_Full);
phylink_set(mac_supported, 50000baseLR_ER_FR_Full);
phylink_set(mac_supported, 50000baseDR_Full);
}
if (!max_speed || (max_speed >= 100000)) {
phylink_set(mac_supported, 100000baseKR4_Full);
phylink_set(mac_supported, 100000baseSR4_Full);
phylink_set(mac_supported, 100000baseCR4_Full);
phylink_set(mac_supported, 100000baseLR4_ER4_Full);
phylink_set(mac_supported, 100000baseKR2_Full);
phylink_set(mac_supported, 100000baseSR2_Full);
phylink_set(mac_supported, 100000baseCR2_Full);
phylink_set(mac_supported, 100000baseLR2_ER2_FR2_Full);
phylink_set(mac_supported, 100000baseDR2_Full);
}
}
/* Half-Duplex can only work with single queue */
if (tx_cnt > 1) {
phylink_set(mask, 10baseT_Half);
phylink_set(mask, 100baseT_Half);
phylink_set(mask, 1000baseT_Half);
}
linkmode_and(supported, supported, mac_supported);
linkmode_andnot(supported, supported, mask);
linkmode_and(state->advertising, state->advertising, mac_supported);
linkmode_andnot(state->advertising, state->advertising, mask);
/* If PCS is supported, check which modes it supports. */ return &priv->hw->xpcs->pcs;
if (priv->hw->xpcs)
xpcs_validate(priv->hw->xpcs, supported, state);
} }
static void stmmac_mac_config(struct phylink_config *config, unsigned int mode, static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
...@@ -1173,7 +1083,8 @@ static void stmmac_mac_link_up(struct phylink_config *config, ...@@ -1173,7 +1083,8 @@ static void stmmac_mac_link_up(struct phylink_config *config,
} }
static const struct phylink_mac_ops stmmac_phylink_mac_ops = { static const struct phylink_mac_ops stmmac_phylink_mac_ops = {
.validate = stmmac_validate, .validate = phylink_generic_validate,
.mac_select_pcs = stmmac_mac_select_pcs,
.mac_config = stmmac_mac_config, .mac_config = stmmac_mac_config,
.mac_link_down = stmmac_mac_link_down, .mac_link_down = stmmac_mac_link_down,
.mac_link_up = stmmac_mac_link_up, .mac_link_up = stmmac_mac_link_up,
...@@ -1253,12 +1164,12 @@ static int stmmac_phy_setup(struct stmmac_priv *priv) ...@@ -1253,12 +1164,12 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
{ {
struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data; struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
struct fwnode_handle *fwnode = of_fwnode_handle(priv->plat->phylink_node); struct fwnode_handle *fwnode = of_fwnode_handle(priv->plat->phylink_node);
int max_speed = priv->plat->max_speed;
int mode = priv->plat->phy_interface; int mode = priv->plat->phy_interface;
struct phylink *phylink; struct phylink *phylink;
priv->phylink_config.dev = &priv->dev->dev; priv->phylink_config.dev = &priv->dev->dev;
priv->phylink_config.type = PHYLINK_NETDEV; priv->phylink_config.type = PHYLINK_NETDEV;
priv->phylink_config.pcs_poll = true;
if (priv->plat->mdio_bus_data) if (priv->plat->mdio_bus_data)
priv->phylink_config.ovr_an_inband = priv->phylink_config.ovr_an_inband =
mdio_bus_data->xpcs_an_inband; mdio_bus_data->xpcs_an_inband;
...@@ -1266,14 +1177,50 @@ static int stmmac_phy_setup(struct stmmac_priv *priv) ...@@ -1266,14 +1177,50 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
if (!fwnode) if (!fwnode)
fwnode = dev_fwnode(priv->device); fwnode = dev_fwnode(priv->device);
/* Set the platform/firmware specified interface mode */
__set_bit(mode, priv->phylink_config.supported_interfaces);
/* If we have an xpcs, it defines which PHY interfaces are supported. */
if (priv->hw->xpcs)
xpcs_get_interfaces(priv->hw->xpcs,
priv->phylink_config.supported_interfaces);
priv->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
MAC_10 | MAC_100;
if (!max_speed || max_speed >= 1000)
priv->phylink_config.mac_capabilities |= MAC_1000;
if (priv->plat->has_gmac4) {
if (!max_speed || max_speed >= 2500)
priv->phylink_config.mac_capabilities |= MAC_2500FD;
} else if (priv->plat->has_xgmac) {
if (!max_speed || max_speed >= 2500)
priv->phylink_config.mac_capabilities |= MAC_2500FD;
if (!max_speed || max_speed >= 5000)
priv->phylink_config.mac_capabilities |= MAC_5000FD;
if (!max_speed || max_speed >= 10000)
priv->phylink_config.mac_capabilities |= MAC_10000FD;
if (!max_speed || max_speed >= 25000)
priv->phylink_config.mac_capabilities |= MAC_25000FD;
if (!max_speed || max_speed >= 40000)
priv->phylink_config.mac_capabilities |= MAC_40000FD;
if (!max_speed || max_speed >= 50000)
priv->phylink_config.mac_capabilities |= MAC_50000FD;
if (!max_speed || max_speed >= 100000)
priv->phylink_config.mac_capabilities |= MAC_100000FD;
}
/* Half-Duplex can only work with single queue */
if (priv->plat->tx_queues_to_use > 1)
priv->phylink_config.mac_capabilities &=
~(MAC_10HD | MAC_100HD | MAC_1000HD);
phylink = phylink_create(&priv->phylink_config, fwnode, phylink = phylink_create(&priv->phylink_config, fwnode,
mode, &stmmac_phylink_mac_ops); mode, &stmmac_phylink_mac_ops);
if (IS_ERR(phylink)) if (IS_ERR(phylink))
return PTR_ERR(phylink); return PTR_ERR(phylink);
if (priv->hw->xpcs)
phylink_set_pcs(phylink, &priv->hw->xpcs->pcs);
priv->phylink = phylink; priv->phylink = phylink;
return 0; return 0;
} }
......
...@@ -632,35 +632,43 @@ static void xpcs_resolve_pma(struct dw_xpcs *xpcs, ...@@ -632,35 +632,43 @@ static void xpcs_resolve_pma(struct dw_xpcs *xpcs,
} }
} }
void xpcs_validate(struct dw_xpcs *xpcs, unsigned long *supported, static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
struct phylink_link_state *state) const struct phylink_link_state *state)
{ {
__ETHTOOL_DECLARE_LINK_MODE_MASK(xpcs_supported); __ETHTOOL_DECLARE_LINK_MODE_MASK(xpcs_supported) = { 0, };
const struct xpcs_compat *compat; const struct xpcs_compat *compat;
struct dw_xpcs *xpcs;
int i; int i;
/* phylink expects us to report all supported modes with xpcs = phylink_pcs_to_xpcs(pcs);
* PHY_INTERFACE_MODE_NA, just don't limit the supported and
* advertising masks and exit.
*/
if (state->interface == PHY_INTERFACE_MODE_NA)
return;
linkmode_zero(xpcs_supported);
compat = xpcs_find_compat(xpcs->id, state->interface); compat = xpcs_find_compat(xpcs->id, state->interface);
/* Populate the supported link modes for this /* Populate the supported link modes for this PHY interface type.
* PHY interface type * FIXME: what about the port modes and autoneg bit? This masks
* all those away.
*/ */
if (compat) if (compat)
for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++) for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
set_bit(compat->supported[i], xpcs_supported); set_bit(compat->supported[i], xpcs_supported);
linkmode_and(supported, supported, xpcs_supported); linkmode_and(supported, supported, xpcs_supported);
linkmode_and(state->advertising, state->advertising, xpcs_supported);
return 0;
}
void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces)
{
int i, j;
for (i = 0; i < DW_XPCS_INTERFACE_MAX; i++) {
const struct xpcs_compat *compat = &xpcs->id->compat[i];
for (j = 0; j < compat->num_interfaces; j++)
if (compat->interface[j] < PHY_INTERFACE_MODE_MAX)
__set_bit(compat->interface[j], interfaces);
}
} }
EXPORT_SYMBOL_GPL(xpcs_validate); EXPORT_SYMBOL_GPL(xpcs_get_interfaces);
int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable) int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable)
{ {
...@@ -1106,6 +1114,7 @@ static const struct xpcs_id xpcs_id_list[] = { ...@@ -1106,6 +1114,7 @@ static const struct xpcs_id xpcs_id_list[] = {
}; };
static const struct phylink_pcs_ops xpcs_phylink_ops = { static const struct phylink_pcs_ops xpcs_phylink_ops = {
.pcs_validate = xpcs_validate,
.pcs_config = xpcs_config, .pcs_config = xpcs_config,
.pcs_get_state = xpcs_get_state, .pcs_get_state = xpcs_get_state,
.pcs_link_up = xpcs_link_up, .pcs_link_up = xpcs_link_up,
......
...@@ -31,8 +31,7 @@ void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode, ...@@ -31,8 +31,7 @@ void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
phy_interface_t interface, int speed, int duplex); phy_interface_t interface, int speed, int duplex);
int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
unsigned int mode); unsigned int mode);
void xpcs_validate(struct dw_xpcs *xpcs, unsigned long *supported, void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces);
struct phylink_link_state *state);
int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns,
int enable); int enable);
struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment