| @@ -331,13 +331,15 @@ static void xgbe_switch_mode(struct xgbe_prv_data *pdata) · 330 unmodified lines |
| 331 | 331 | xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata)); |
| 332 | 332 | } |
| 333 | 333 | |
| 334 | | −static void xgbe_set_mode(struct xgbe_prv_data *pdata, |
| 334 | +static bool xgbe_set_mode(struct xgbe_prv_data *pdata, |
| 335 | 335 | enum xgbe_mode mode) |
| 336 | 336 | { |
| 337 | 337 | if (mode == xgbe_cur_mode(pdata)) |
| 338 | | − return; |
| 338 | + return false; |
| 339 | 339 | |
| 340 | 340 | xgbe_change_mode(pdata, mode); |
| 341 | + |
| 342 | + return true; |
| 341 | 343 | } |
| 342 | 344 | |
| 343 | 345 | 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 |
| 1178 | 1180 | return 0; |
| 1179 | 1181 | } |
| 1180 | 1182 | |
| 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) |
| 1182 | 1184 | { |
| 1183 | 1185 | int ret; |
| 1184 | 1186 | |
| 1187 | + mutex_lock(&pdata->an_mutex); |
| 1188 | + |
| 1185 | 1189 | set_bit(XGBE_LINK_INIT, &pdata->dev_state); |
| 1186 | 1190 | pdata->link_check = jiffies; |
| 1187 | 1191 | |
| 1188 | 1192 | ret = pdata->phy_if.phy_impl.an_config(pdata); |
| 1189 | 1193 | if (ret) |
| 1190 | | − return ret; |
| 1194 | + goto out; |
| 1191 | 1195 | |
| 1192 | 1196 | if (pdata->phy.autoneg != AUTONEG_ENABLE) { |
| 1193 | 1197 | ret = xgbe_phy_config_fixed(pdata); |
| 1194 | 1198 | if (ret || !pdata->kr_redrv) |
| 1195 | | − return ret; |
| 1199 | + goto out; |
| 1196 | 1200 | |
| 1197 | 1201 | netif_dbg(pdata, link, pdata->netdev, "AN redriver support\n"); |
| 1198 | 1202 | } else { |
| @@ -1202,24 +1206,27 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) · 3 unmodified lines |
| 1202 | 1206 | /* Disable auto-negotiation interrupt */ |
| 1203 | 1207 | disable_irq(pdata->an_irq); |
| 1204 | 1208 | |
| 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 | + } |
| 1223 | 1230 | } |
| 1224 | 1231 | |
| 1225 | 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 | 1246 | xgbe_an_init(pdata); |
| 1240 | 1247 | xgbe_an_restart(pdata); |
| 1241 | 1248 | |
| 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: |
| 1252 | 1250 | if (ret) |
| 1253 | 1251 | set_bit(XGBE_LINK_ERR, &pdata->dev_state); |
| 1254 | 1252 | else |
| @@ -1259,6 +1257,16 @@ static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) · 4 unmodified lines |
| 1259 | 1257 | return ret; |
| 1260 | 1258 | } |
| 1261 | 1259 | |
| 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 | + |
| 1262 | 1270 | static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata) |
| 1263 | 1271 | { |
| 1264 | 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 | 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 | |
| 1321 | 1330 | static void xgbe_phy_status(struct xgbe_prv_data *pdata) |