History

amd-xgbe: Improve SFP 100Mbps auto-negotiation

After changing speed to 100Mbps as a result of auto-negotiation (AN), some 10/100/1000Mbps SFPs indicate a successful link (no faults or loss of signal), but cannot successfully transmit or receive data. These SFPs required an extra auto-negotiation (AN) after the speed change in order to operate properly. Add a quirk for these SFPs so that if the outcome of the AN actually results in changing to a new speed, re-initiate AN at that new speed.

Tom Lendacky committed 8 years ago

Commit 76cce0a1 parent e722ec83 files · +50 −34Browse files

Unified · Split

3 files
  1. drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +43 −34
  2. drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +6 −0
  3. drivers/net/ethernet/amd/xgbe/xgbe.h +1 −0
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c+43−34
@@ -331,13 +331,15 @@ static void xgbe_switch_mode(struct xgbe_prv_data *pdata) · 330 unmodified lines
331 xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata));331 xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata));
332}332}
333 333
334static void xgbe_set_mode(struct xgbe_prv_data *pdata,334static bool xgbe_set_mode(struct xgbe_prv_data *pdata,
335 enum xgbe_mode mode)335 enum xgbe_mode mode)
336{336{
337 if (mode == xgbe_cur_mode(pdata))337 if (mode == xgbe_cur_mode(pdata))
338 return;338 return false;
339 339
340 xgbe_change_mode(pdata, mode);340 xgbe_change_mode(pdata, mode);
341
342 return true;
341}343}
342 344
343static bool xgbe_use_mode(struct xgbe_prv_data *pdata,345static bool xgbe_use_mode(struct xgbe_prv_data *pdata,
@@ -1178,21 +1180,23 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata) · 834 unmodified lines
1178 return 0;1180 return 0;
1179}1181}
1180 1182
1181static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)1183static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode)
1182{1184{
1183 int ret;1185 int ret;
1184 1186
1187 mutex_lock(&pdata->an_mutex);
1188
1185 set_bit(XGBE_LINK_INIT, &pdata->dev_state);1189 set_bit(XGBE_LINK_INIT, &pdata->dev_state);
1186 pdata->link_check = jiffies;1190 pdata->link_check = jiffies;
1187 1191
1188 ret = pdata->phy_if.phy_impl.an_config(pdata);1192 ret = pdata->phy_if.phy_impl.an_config(pdata);
1189 if (ret)1193 if (ret)
1190 return ret;1194 goto out;
1191 1195
1192 if (pdata->phy.autoneg != AUTONEG_ENABLE) {1196 if (pdata->phy.autoneg != AUTONEG_ENABLE) {
1193 ret = xgbe_phy_config_fixed(pdata);1197 ret = xgbe_phy_config_fixed(pdata);
1194 if (ret || !pdata->kr_redrv)1198 if (ret || !pdata->kr_redrv)
1195 return ret;1199 goto out;
1196 1200
1197 netif_dbg(pdata, link, pdata->netdev, "AN redriver support\n");1201 netif_dbg(pdata, link, pdata->netdev, "AN redriver support\n");
1198 } else {1202 } else {
@@ -1202,24 +1206,27 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) · 3 unmodified lines
1202 /* Disable auto-negotiation interrupt */1206 /* Disable auto-negotiation interrupt */
1203 disable_irq(pdata->an_irq);1207 disable_irq(pdata->an_irq);
1204 1208
1205 /* Start auto-negotiation in a supported mode */1209 if (set_mode) {
1206 if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {1210 /* Start auto-negotiation in a supported mode */
1207 xgbe_set_mode(pdata, XGBE_MODE_KR);1211 if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
1208 } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {1212 xgbe_set_mode(pdata, XGBE_MODE_KR);
1209 xgbe_set_mode(pdata, XGBE_MODE_KX_2500);1213 } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
1210 } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {1214 xgbe_set_mode(pdata, XGBE_MODE_KX_2500);
1211 xgbe_set_mode(pdata, XGBE_MODE_KX_1000);1215 } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
1212 } else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {1216 xgbe_set_mode(pdata, XGBE_MODE_KX_1000);
1213 xgbe_set_mode(pdata, XGBE_MODE_SFI);1217 } else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
1214 } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {1218 xgbe_set_mode(pdata, XGBE_MODE_SFI);
1215 xgbe_set_mode(pdata, XGBE_MODE_X);1219 } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
1216 } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {1220 xgbe_set_mode(pdata, XGBE_MODE_X);
1217 xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);1221 } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
1218 } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {1222 xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);
1219 xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);1223 } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
1220 } else {1224 xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);
1221 enable_irq(pdata->an_irq);1225 } else {
1222 return -EINVAL;1226 enable_irq(pdata->an_irq);
1227 ret = -EINVAL;
1228 goto out;
1229 }
1223 }1230 }
1224 1231
1225 /* Disable and stop any in progress auto-negotiation */1232 /* Disable and stop any in progress auto-negotiation */
@@ -1239,16 +1246,7 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) · 13 unmodified lines
1239 xgbe_an_init(pdata);1246 xgbe_an_init(pdata);
1240 xgbe_an_restart(pdata);1247 xgbe_an_restart(pdata);
1241 1248
1242 return 0;1249out:
1243}
1244
1245static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
1246{
1247 int ret;
1248
1249 mutex_lock(&pdata->an_mutex);
1250
1251 ret = __xgbe_phy_config_aneg(pdata);
1252 if (ret)1250 if (ret)
1253 set_bit(XGBE_LINK_ERR, &pdata->dev_state);1251 set_bit(XGBE_LINK_ERR, &pdata->dev_state);
1254 else1252 else
@@ -1259,6 +1257,16 @@ static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) · 4 unmodified lines
1259 return ret;1257 return ret;
1260}1258}
1261 1259
1260static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
1261{
1262 return __xgbe_phy_config_aneg(pdata, true);
1263}
1264
1265static int xgbe_phy_reconfig_aneg(struct xgbe_prv_data *pdata)
1266{
1267 return __xgbe_phy_config_aneg(pdata, false);
1268}
1269
1262static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)1270static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)
1263{1271{
1264 return (pdata->an_result == XGBE_AN_COMPLETE);1272 return (pdata->an_result == XGBE_AN_COMPLETE);
@@ -1315,7 +1323,8 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata) · 50 unmodified lines
1315 1323
1316 pdata->phy.duplex = DUPLEX_FULL;1324 pdata->phy.duplex = DUPLEX_FULL;
1317 1325
1318 xgbe_set_mode(pdata, mode);1326 if (xgbe_set_mode(pdata, mode) && pdata->an_again)
1327 xgbe_phy_reconfig_aneg(pdata);
1319}1328}
1320 1329
1321static void xgbe_phy_status(struct xgbe_prv_data *pdata)1330static void xgbe_phy_status(struct xgbe_prv_data *pdata)
drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c+6−0
@@ -902,6 +902,9 @@ static bool xgbe_phy_belfuse_phy_quirks(struct xgbe_prv_data *pdata) · 901 unmodified lines
902 XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN))902 XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN))
903 return false;903 return false;
904 904
905 /* For Bel-Fuse, use the extra AN flag */
906 pdata->an_again = 1;
907
905 if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN],908 if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN],
906 XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN))909 XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN))
907 return false;910 return false;
@@ -978,6 +981,9 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) · 70 unmodified lines
978 if (phy_data->phydev)981 if (phy_data->phydev)
979 return 0;982 return 0;
980 983
984 /* Clear the extra AN flag */
985 pdata->an_again = 0;
986
981 /* Check for the use of an external PHY */987 /* Check for the use of an external PHY */
982 if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE)988 if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE)
983 return 0;989 return 0;
drivers/net/ethernet/amd/xgbe/xgbe.h+1−0
@@ -1261,6 +1261,7 @@ struct xgbe_prv_data { · 1260 unmodified lines
1261 enum xgbe_rx kr_state;1261 enum xgbe_rx kr_state;
1262 enum xgbe_rx kx_state;1262 enum xgbe_rx kx_state;
1263 struct work_struct an_work;1263 struct work_struct an_work;
1264 unsigned int an_again;
1264 unsigned int an_supported;1265 unsigned int an_supported;
1265 unsigned int parallel_detect;1266 unsigned int parallel_detect;
1266 unsigned int fec_ability;1267 unsigned int fec_ability;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t