Skip to content

Commit df874f9

Browse files
Russell King (Oracle)kuba-moo
authored andcommitted
net: phylink: add pcs_inband_caps() method
Add a pcs_inband_caps() method to query the PCS for its inband link capabilities, and use this to determine whether link modes used with optical SFPs can be supported. When a PCS does not provide a method, we allow inband negotiation to be either on or off, making this a no-op until the pcs_inband_caps() method is implemented by a PCS driver. Reviewed-by: Andrew Lunn <[email protected]> Signed-off-by: Russell King (Oracle) <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent a219912 commit df874f9

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

drivers/net/phy/phylink.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,15 @@ static void phylink_resolve_an_pause(struct phylink_link_state *state)
990990
}
991991
}
992992

993+
static unsigned int phylink_pcs_inband_caps(struct phylink_pcs *pcs,
994+
phy_interface_t interface)
995+
{
996+
if (pcs && pcs->ops->pcs_inband_caps)
997+
return pcs->ops->pcs_inband_caps(pcs, interface);
998+
999+
return 0;
1000+
}
1001+
9931002
static void phylink_pcs_pre_config(struct phylink_pcs *pcs,
9941003
phy_interface_t interface)
9951004
{
@@ -1043,6 +1052,24 @@ static void phylink_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
10431052
pcs->ops->pcs_link_up(pcs, neg_mode, interface, speed, duplex);
10441053
}
10451054

1055+
/* Query inband for a specific interface mode, asking the MAC for the
1056+
* PCS which will be used to handle the interface mode.
1057+
*/
1058+
static unsigned int phylink_inband_caps(struct phylink *pl,
1059+
phy_interface_t interface)
1060+
{
1061+
struct phylink_pcs *pcs;
1062+
1063+
if (!pl->mac_ops->mac_select_pcs)
1064+
return 0;
1065+
1066+
pcs = pl->mac_ops->mac_select_pcs(pl->config, interface);
1067+
if (!pcs)
1068+
return 0;
1069+
1070+
return phylink_pcs_inband_caps(pcs, interface);
1071+
}
1072+
10461073
static void phylink_pcs_poll_stop(struct phylink *pl)
10471074
{
10481075
if (pl->cfg_link_an_mode == MLO_AN_INBAND)
@@ -2532,6 +2559,26 @@ int phylink_ethtool_ksettings_get(struct phylink *pl,
25322559
}
25332560
EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_get);
25342561

2562+
static bool phylink_validate_pcs_inband_autoneg(struct phylink *pl,
2563+
phy_interface_t interface,
2564+
unsigned long *adv)
2565+
{
2566+
unsigned int inband = phylink_inband_caps(pl, interface);
2567+
unsigned int mask;
2568+
2569+
/* If the PCS doesn't implement inband support, be permissive. */
2570+
if (!inband)
2571+
return true;
2572+
2573+
if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, adv))
2574+
mask = LINK_INBAND_ENABLE;
2575+
else
2576+
mask = LINK_INBAND_DISABLE;
2577+
2578+
/* Check whether the PCS implements the required mode */
2579+
return !!(inband & mask);
2580+
}
2581+
25352582
/**
25362583
* phylink_ethtool_ksettings_set() - set the link settings
25372584
* @pl: a pointer to a &struct phylink returned from phylink_create()
@@ -2662,6 +2709,13 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
26622709
phylink_is_empty_linkmode(config.advertising))
26632710
return -EINVAL;
26642711

2712+
/* Validate the autonegotiation state. We don't have a PHY in this
2713+
* situation, so the PCS is the media-facing entity.
2714+
*/
2715+
if (!phylink_validate_pcs_inband_autoneg(pl, config.interface,
2716+
config.advertising))
2717+
return -EINVAL;
2718+
26652719
mutex_lock(&pl->state_mutex);
26662720
pl->link_config.speed = config.speed;
26672721
pl->link_config.duplex = config.duplex;
@@ -3341,6 +3395,12 @@ static int phylink_sfp_config_optical(struct phylink *pl)
33413395
phylink_dbg(pl, "optical SFP: chosen %s interface\n",
33423396
phy_modes(interface));
33433397

3398+
if (!phylink_validate_pcs_inband_autoneg(pl, interface,
3399+
config.advertising)) {
3400+
phylink_err(pl, "autoneg setting not compatible with PCS");
3401+
return -EINVAL;
3402+
}
3403+
33443404
config.interface = interface;
33453405

33463406
/* Ignore errors if we're expecting a PHY to attach later */

include/linux/phylink.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ struct phylink_pcs {
419419
/**
420420
* struct phylink_pcs_ops - MAC PCS operations structure.
421421
* @pcs_validate: validate the link configuration.
422+
* @pcs_inband_caps: query inband support for interface mode.
422423
* @pcs_enable: enable the PCS.
423424
* @pcs_disable: disable the PCS.
424425
* @pcs_pre_config: pre-mac_config method (for errata)
@@ -434,6 +435,8 @@ struct phylink_pcs {
434435
struct phylink_pcs_ops {
435436
int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported,
436437
const struct phylink_link_state *state);
438+
unsigned int (*pcs_inband_caps)(struct phylink_pcs *pcs,
439+
phy_interface_t interface);
437440
int (*pcs_enable)(struct phylink_pcs *pcs);
438441
void (*pcs_disable)(struct phylink_pcs *pcs);
439442
void (*pcs_pre_config)(struct phylink_pcs *pcs,
@@ -470,6 +473,20 @@ struct phylink_pcs_ops {
470473
int pcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
471474
const struct phylink_link_state *state);
472475

476+
/**
477+
* pcs_inband_caps - query PCS in-band capabilities for interface mode.
478+
* @pcs: a pointer to a &struct phylink_pcs.
479+
* @interface: interface mode to be queried
480+
*
481+
* Returns zero if it is unknown what in-band signalling is supported by the
482+
* PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise,
483+
* returns a bit mask of the LINK_INBAND_* values from
484+
* &enum link_inband_signalling to describe which inband modes are supported
485+
* for this interface mode.
486+
*/
487+
unsigned int pcs_inband_caps(struct phylink_pcs *pcs,
488+
phy_interface_t interface);
489+
473490
/**
474491
* pcs_enable() - enable the PCS.
475492
* @pcs: a pointer to a &struct phylink_pcs.

0 commit comments

Comments
 (0)