Skip to content

Commit 5fd0f1a

Browse files
Russell King (Oracle)kuba-moo
authored andcommitted
net: phylink: add negotiation of in-band capabilities
Support for in-band signalling with Serdes links is uncertain. Some PHYs do not support in-band for e.g. SGMII. Some PCS do not support in-band for 2500Base-X. Some PCS require in-band for Base-X protocols. Simply using what is in DT is insufficient when we have hot-pluggable PHYs e.g. in the form of SFP modules, which may not provide the in-band signalling. In order to address this, we have introduced phy_inband_caps() and pcs_inband_caps() functions to allow phylink to retrieve the capabilities from each end of the PCS/PHY link. This commit adds code to resolve whether in-band will be used in the various scenarios that we have: In-band not being used, PHY present using SGMII or Base-X, PHY not present. We also deal with no capabilties provided. Signed-off-by: Russell King (Oracle) <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent d4169f0 commit 5fd0f1a

File tree

1 file changed

+144
-10
lines changed

1 file changed

+144
-10
lines changed

drivers/net/phy/phylink.c

Lines changed: 144 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct phylink {
7575

7676
struct mutex state_mutex;
7777
struct phylink_link_state phy_state;
78+
unsigned int phy_ib_mode;
7879
struct work_struct resolve;
7980
unsigned int pcs_neg_mode;
8081
unsigned int pcs_state;
@@ -1153,10 +1154,18 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs,
11531154
phy_interface_t interface,
11541155
const unsigned long *advertising)
11551156
{
1157+
unsigned int pcs_ib_caps = 0;
1158+
unsigned int phy_ib_caps = 0;
11561159
unsigned int neg_mode, mode;
1160+
enum {
1161+
INBAND_CISCO_SGMII,
1162+
INBAND_BASEX,
1163+
} type;
11571164

11581165
mode = pl->req_link_an_mode;
11591166

1167+
pl->phy_ib_mode = 0;
1168+
11601169
switch (interface) {
11611170
case PHY_INTERFACE_MODE_SGMII:
11621171
case PHY_INTERFACE_MODE_QSGMII:
@@ -1168,10 +1177,7 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs,
11681177
* inband communication. Note: there exist PHYs that run
11691178
* with SGMII but do not send the inband data.
11701179
*/
1171-
if (!phylink_autoneg_inband(mode))
1172-
neg_mode = PHYLINK_PCS_NEG_OUTBAND;
1173-
else
1174-
neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
1180+
type = INBAND_CISCO_SGMII;
11751181
break;
11761182

11771183
case PHY_INTERFACE_MODE_1000BASEX:
@@ -1182,18 +1188,139 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs,
11821188
* as well, but drivers may not support this, so may
11831189
* need to override this.
11841190
*/
1185-
if (!phylink_autoneg_inband(mode))
1191+
type = INBAND_BASEX;
1192+
break;
1193+
1194+
default:
1195+
pl->pcs_neg_mode = PHYLINK_PCS_NEG_NONE;
1196+
pl->act_link_an_mode = mode;
1197+
return;
1198+
}
1199+
1200+
if (pcs)
1201+
pcs_ib_caps = phylink_pcs_inband_caps(pcs, interface);
1202+
1203+
if (pl->phydev)
1204+
phy_ib_caps = phy_inband_caps(pl->phydev, interface);
1205+
1206+
phylink_dbg(pl, "interface %s inband modes: pcs=%02x phy=%02x\n",
1207+
phy_modes(interface), pcs_ib_caps, phy_ib_caps);
1208+
1209+
if (!phylink_autoneg_inband(mode)) {
1210+
bool pcs_ib_only = false;
1211+
bool phy_ib_only = false;
1212+
1213+
if (pcs_ib_caps && pcs_ib_caps != LINK_INBAND_DISABLE) {
1214+
/* PCS supports reporting in-band capabilities, and
1215+
* supports more than disable mode.
1216+
*/
1217+
if (pcs_ib_caps & LINK_INBAND_DISABLE)
1218+
neg_mode = PHYLINK_PCS_NEG_OUTBAND;
1219+
else if (pcs_ib_caps & LINK_INBAND_ENABLE)
1220+
pcs_ib_only = true;
1221+
}
1222+
1223+
if (phy_ib_caps && phy_ib_caps != LINK_INBAND_DISABLE) {
1224+
/* PHY supports in-band capabilities, and supports
1225+
* more than disable mode.
1226+
*/
1227+
if (phy_ib_caps & LINK_INBAND_DISABLE)
1228+
pl->phy_ib_mode = LINK_INBAND_DISABLE;
1229+
else if (phy_ib_caps & LINK_INBAND_BYPASS)
1230+
pl->phy_ib_mode = LINK_INBAND_BYPASS;
1231+
else if (phy_ib_caps & LINK_INBAND_ENABLE)
1232+
phy_ib_only = true;
1233+
}
1234+
1235+
/* If either the PCS or PHY requires inband to be enabled,
1236+
* this is an invalid configuration. Provide a diagnostic
1237+
* message for this case, but don't try to force the issue.
1238+
*/
1239+
if (pcs_ib_only || phy_ib_only)
1240+
phylink_warn(pl,
1241+
"firmware wants %s mode, but %s%s%s requires inband\n",
1242+
phylink_an_mode_str(mode),
1243+
pcs_ib_only ? "PCS" : "",
1244+
pcs_ib_only && phy_ib_only ? " and " : "",
1245+
phy_ib_only ? "PHY" : "");
1246+
1247+
neg_mode = PHYLINK_PCS_NEG_OUTBAND;
1248+
} else if (type == INBAND_CISCO_SGMII || pl->phydev) {
1249+
/* For SGMII modes which are designed to be used with PHYs, or
1250+
* Base-X with a PHY, we try to use in-band mode where-ever
1251+
* possible. However, there are some PHYs e.g. BCM84881 which
1252+
* do not support in-band.
1253+
*/
1254+
const unsigned int inband_ok = LINK_INBAND_ENABLE |
1255+
LINK_INBAND_BYPASS;
1256+
const unsigned int outband_ok = LINK_INBAND_DISABLE |
1257+
LINK_INBAND_BYPASS;
1258+
/* PCS PHY
1259+
* D E D E
1260+
* 0 0 0 0 no information inband enabled
1261+
* 1 0 0 0 pcs doesn't support outband
1262+
* 0 1 0 0 pcs required inband enabled
1263+
* 1 1 0 0 pcs optional inband enabled
1264+
* 0 0 1 0 phy doesn't support outband
1265+
* 1 0 1 0 pcs+phy doesn't support outband
1266+
* 0 1 1 0 pcs required, phy doesn't support, invalid
1267+
* 1 1 1 0 pcs optional, phy doesn't support, outband
1268+
* 0 0 0 1 phy required inband enabled
1269+
* 1 0 0 1 pcs doesn't support, phy required, invalid
1270+
* 0 1 0 1 pcs+phy required inband enabled
1271+
* 1 1 0 1 pcs optional, phy required inband enabled
1272+
* 0 0 1 1 phy optional inband enabled
1273+
* 1 0 1 1 pcs doesn't support, phy optional, outband
1274+
* 0 1 1 1 pcs required, phy optional inband enabled
1275+
* 1 1 1 1 pcs+phy optional inband enabled
1276+
*/
1277+
if ((!pcs_ib_caps || pcs_ib_caps & inband_ok) &&
1278+
(!phy_ib_caps || phy_ib_caps & inband_ok)) {
1279+
/* In-band supported or unknown at both ends. Enable
1280+
* in-band mode with or without bypass at the PHY.
1281+
*/
1282+
if (phy_ib_caps & LINK_INBAND_ENABLE)
1283+
pl->phy_ib_mode = LINK_INBAND_ENABLE;
1284+
else if (phy_ib_caps & LINK_INBAND_BYPASS)
1285+
pl->phy_ib_mode = LINK_INBAND_BYPASS;
1286+
1287+
neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
1288+
} else if ((!pcs_ib_caps || pcs_ib_caps & outband_ok) &&
1289+
(!phy_ib_caps || phy_ib_caps & outband_ok)) {
1290+
/* Either in-band not supported at at least one end.
1291+
* In-band bypass at the other end is possible.
1292+
*/
1293+
if (phy_ib_caps & LINK_INBAND_DISABLE)
1294+
pl->phy_ib_mode = LINK_INBAND_DISABLE;
1295+
else if (phy_ib_caps & LINK_INBAND_BYPASS)
1296+
pl->phy_ib_mode = LINK_INBAND_BYPASS;
1297+
11861298
neg_mode = PHYLINK_PCS_NEG_OUTBAND;
1299+
if (pl->phydev)
1300+
mode = MLO_AN_PHY;
1301+
} else {
1302+
/* invalid */
1303+
phylink_warn(pl, "%s: incompatible in-band capabilities, trying in-band",
1304+
phy_modes(interface));
1305+
neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
1306+
}
1307+
} else {
1308+
/* For Base-X without a PHY */
1309+
if (pcs_ib_caps == LINK_INBAND_DISABLE)
1310+
/* If the PCS doesn't support inband, then inband must
1311+
* be disabled.
1312+
*/
1313+
neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
1314+
else if (pcs_ib_caps == LINK_INBAND_ENABLE)
1315+
/* If the PCS requires inband, then inband must always
1316+
* be enabled.
1317+
*/
1318+
neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
11871319
else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
11881320
advertising))
11891321
neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
11901322
else
11911323
neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
1192-
break;
1193-
1194-
default:
1195-
neg_mode = PHYLINK_PCS_NEG_NONE;
1196-
break;
11971324
}
11981325

11991326
pl->pcs_neg_mode = neg_mode;
@@ -1292,6 +1419,13 @@ static void phylink_major_config(struct phylink *pl, bool restart,
12921419
ERR_PTR(err));
12931420
}
12941421

1422+
if (pl->phydev && pl->phy_ib_mode) {
1423+
err = phy_config_inband(pl->phydev, pl->phy_ib_mode);
1424+
if (err < 0)
1425+
phylink_err(pl, "phy_config_inband: %pe\n",
1426+
ERR_PTR(err));
1427+
}
1428+
12951429
if (pl->sfp_bus) {
12961430
rate_kbd = phylink_interface_signal_rate(state->interface);
12971431
if (rate_kbd)

0 commit comments

Comments
 (0)