@@ -990,6 +990,15 @@ static void phylink_resolve_an_pause(struct phylink_link_state *state)
990
990
}
991
991
}
992
992
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
+
993
1002
static void phylink_pcs_pre_config (struct phylink_pcs * pcs ,
994
1003
phy_interface_t interface )
995
1004
{
@@ -1043,6 +1052,24 @@ static void phylink_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
1043
1052
pcs -> ops -> pcs_link_up (pcs , neg_mode , interface , speed , duplex );
1044
1053
}
1045
1054
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
+
1046
1073
static void phylink_pcs_poll_stop (struct phylink * pl )
1047
1074
{
1048
1075
if (pl -> cfg_link_an_mode == MLO_AN_INBAND )
@@ -2532,6 +2559,26 @@ int phylink_ethtool_ksettings_get(struct phylink *pl,
2532
2559
}
2533
2560
EXPORT_SYMBOL_GPL (phylink_ethtool_ksettings_get );
2534
2561
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
+
2535
2582
/**
2536
2583
* phylink_ethtool_ksettings_set() - set the link settings
2537
2584
* @pl: a pointer to a &struct phylink returned from phylink_create()
@@ -2662,6 +2709,13 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
2662
2709
phylink_is_empty_linkmode (config .advertising ))
2663
2710
return - EINVAL ;
2664
2711
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
+
2665
2719
mutex_lock (& pl -> state_mutex );
2666
2720
pl -> link_config .speed = config .speed ;
2667
2721
pl -> link_config .duplex = config .duplex ;
@@ -3341,6 +3395,12 @@ static int phylink_sfp_config_optical(struct phylink *pl)
3341
3395
phylink_dbg (pl , "optical SFP: chosen %s interface\n" ,
3342
3396
phy_modes (interface ));
3343
3397
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
+
3344
3404
config .interface = interface ;
3345
3405
3346
3406
/* Ignore errors if we're expecting a PHY to attach later */
0 commit comments