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
331331 xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata));
332332 }
333333
334−static void xgbe_set_mode(struct xgbe_prv_data *pdata,
334+static bool xgbe_set_mode(struct xgbe_prv_data *pdata,
335335 enum xgbe_mode mode)
336336 {
337337 if (mode == xgbe_cur_mode(pdata))
338− return;
338+ return false;
339339
340340 xgbe_change_mode(pdata, mode);
341+
342+ return true;
341343 }
342344
343345 static 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
11781180 return 0;
11791181 }
11801182
1181−static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
1183+static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode)
11821184 {
11831185 int ret;
11841186
1187+ mutex_lock(&pdata->an_mutex);
1188+
11851189 set_bit(XGBE_LINK_INIT, &pdata->dev_state);
11861190 pdata->link_check = jiffies;
11871191
11881192 ret = pdata->phy_if.phy_impl.an_config(pdata);
11891193 if (ret)
1190− return ret;
1194+ goto out;
11911195
11921196 if (pdata->phy.autoneg != AUTONEG_ENABLE) {
11931197 ret = xgbe_phy_config_fixed(pdata);
11941198 if (ret || !pdata->kr_redrv)
1195− return ret;
1199+ goto out;
11961200
11971201 netif_dbg(pdata, link, pdata->netdev, "AN redriver support\n");
11981202 } else {
@@ -1202,24 +1206,27 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) · 3 unmodified lines
12021206 /* Disable auto-negotiation interrupt */
12031207 disable_irq(pdata->an_irq);
12041208
1205− /* Start auto-negotiation in a supported mode */
1206− if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
1207− xgbe_set_mode(pdata, XGBE_MODE_KR);
1208− } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
1209− xgbe_set_mode(pdata, XGBE_MODE_KX_2500);
1210− } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
1211− xgbe_set_mode(pdata, XGBE_MODE_KX_1000);
1212− } else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
1213− xgbe_set_mode(pdata, XGBE_MODE_SFI);
1214− } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
1215− xgbe_set_mode(pdata, XGBE_MODE_X);
1216− } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
1217− xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);
1218− } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
1219− xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);
1220− } else {
1221− enable_irq(pdata->an_irq);
1222− return -EINVAL;
1209+ if (set_mode) {
1210+ /* Start auto-negotiation in a supported mode */
1211+ if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
1212+ xgbe_set_mode(pdata, XGBE_MODE_KR);
1213+ } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
1214+ xgbe_set_mode(pdata, XGBE_MODE_KX_2500);
1215+ } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
1216+ xgbe_set_mode(pdata, XGBE_MODE_KX_1000);
1217+ } else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
1218+ xgbe_set_mode(pdata, XGBE_MODE_SFI);
1219+ } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
1220+ xgbe_set_mode(pdata, XGBE_MODE_X);
1221+ } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
1222+ xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);
1223+ } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
1224+ xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);
1225+ } else {
1226+ enable_irq(pdata->an_irq);
1227+ ret = -EINVAL;
1228+ goto out;
1229+ }
12231230 }
12241231
12251232 /* 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
12391246 xgbe_an_init(pdata);
12401247 xgbe_an_restart(pdata);
12411248
1242− return 0;
1243−}
1244−
1245−static 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);
1249+out:
12521250 if (ret)
12531251 set_bit(XGBE_LINK_ERR, &pdata->dev_state);
12541252 else
@@ -1259,6 +1257,16 @@ static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) · 4 unmodified lines
12591257 return ret;
12601258 }
12611259
1260+static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
1261+{
1262+ return __xgbe_phy_config_aneg(pdata, true);
1263+}
1264+
1265+static int xgbe_phy_reconfig_aneg(struct xgbe_prv_data *pdata)
1266+{
1267+ return __xgbe_phy_config_aneg(pdata, false);
1268+}
1269+
12621270 static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)
12631271 {
12641272 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
13151323
13161324 pdata->phy.duplex = DUPLEX_FULL;
13171325
1318− xgbe_set_mode(pdata, mode);
1326+ if (xgbe_set_mode(pdata, mode) && pdata->an_again)
1327+ xgbe_phy_reconfig_aneg(pdata);
13191328 }
13201329
13211330 static 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
902902 XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN))
903903 return false;
904904
905+ /* For Bel-Fuse, use the extra AN flag */
906+ pdata->an_again = 1;
907+
905908 if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN],
906909 XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN))
907910 return false;
@@ -978,6 +981,9 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) · 70 unmodified lines
978981 if (phy_data->phydev)
979982 return 0;
980983
984+ /* Clear the extra AN flag */
985+ pdata->an_again = 0;
986+
981987 /* Check for the use of an external PHY */
982988 if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE)
983989 return 0;
drivers/net/ethernet/amd/xgbe/xgbe.h+1−0
@@ -1261,6 +1261,7 @@ struct xgbe_prv_data { · 1260 unmodified lines
12611261 enum xgbe_rx kr_state;
12621262 enum xgbe_rx kx_state;
12631263 struct work_struct an_work;
1264+ unsigned int an_again;
12641265 unsigned int an_supported;
12651266 unsigned int parallel_detect;
12661267 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