diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/sfc/mdio_10g.c | 108 |
1 files changed, 39 insertions, 69 deletions
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 25fb20adf4b7..231e580acc9a 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c | |||
@@ -248,7 +248,7 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx, | |||
248 | int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) | 248 | int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) |
249 | { | 249 | { |
250 | struct ethtool_cmd prev; | 250 | struct ethtool_cmd prev; |
251 | u32 required; | 251 | bool xnp; |
252 | int reg; | 252 | int reg; |
253 | 253 | ||
254 | efx->phy_op->get_settings(efx, &prev); | 254 | efx->phy_op->get_settings(efx, &prev); |
@@ -265,76 +265,46 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) | |||
265 | return -EINVAL; | 265 | return -EINVAL; |
266 | 266 | ||
267 | /* Check that PHY supports these settings */ | 267 | /* Check that PHY supports these settings */ |
268 | if (ecmd->autoneg) { | 268 | if (!ecmd->autoneg || |
269 | required = SUPPORTED_Autoneg; | 269 | (ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported) |
270 | } else if (ecmd->duplex) { | ||
271 | switch (ecmd->speed) { | ||
272 | case SPEED_10: required = SUPPORTED_10baseT_Full; break; | ||
273 | case SPEED_100: required = SUPPORTED_100baseT_Full; break; | ||
274 | default: return -EINVAL; | ||
275 | } | ||
276 | } else { | ||
277 | switch (ecmd->speed) { | ||
278 | case SPEED_10: required = SUPPORTED_10baseT_Half; break; | ||
279 | case SPEED_100: required = SUPPORTED_100baseT_Half; break; | ||
280 | default: return -EINVAL; | ||
281 | } | ||
282 | } | ||
283 | required |= ecmd->advertising; | ||
284 | if (required & ~prev.supported) | ||
285 | return -EINVAL; | 270 | return -EINVAL; |
286 | 271 | ||
287 | if (ecmd->autoneg) { | 272 | xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full |
288 | bool xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full | 273 | || EFX_WORKAROUND_13204(efx)); |
289 | || EFX_WORKAROUND_13204(efx)); | 274 | |
290 | 275 | /* Set up the base page */ | |
291 | /* Set up the base page */ | 276 | reg = ADVERTISE_CSMA; |
292 | reg = ADVERTISE_CSMA; | 277 | if (ecmd->advertising & ADVERTISED_10baseT_Half) |
293 | if (ecmd->advertising & ADVERTISED_10baseT_Half) | 278 | reg |= ADVERTISE_10HALF; |
294 | reg |= ADVERTISE_10HALF; | 279 | if (ecmd->advertising & ADVERTISED_10baseT_Full) |
295 | if (ecmd->advertising & ADVERTISED_10baseT_Full) | 280 | reg |= ADVERTISE_10FULL; |
296 | reg |= ADVERTISE_10FULL; | 281 | if (ecmd->advertising & ADVERTISED_100baseT_Half) |
297 | if (ecmd->advertising & ADVERTISED_100baseT_Half) | 282 | reg |= ADVERTISE_100HALF; |
298 | reg |= ADVERTISE_100HALF; | 283 | if (ecmd->advertising & ADVERTISED_100baseT_Full) |
299 | if (ecmd->advertising & ADVERTISED_100baseT_Full) | 284 | reg |= ADVERTISE_100FULL; |
300 | reg |= ADVERTISE_100FULL; | 285 | if (xnp) |
301 | if (xnp) | 286 | reg |= ADVERTISE_RESV; |
302 | reg |= ADVERTISE_RESV; | 287 | else if (ecmd->advertising & (ADVERTISED_1000baseT_Half | |
303 | else if (ecmd->advertising & (ADVERTISED_1000baseT_Half | | 288 | ADVERTISED_1000baseT_Full)) |
304 | ADVERTISED_1000baseT_Full)) | 289 | reg |= ADVERTISE_NPAGE; |
305 | reg |= ADVERTISE_NPAGE; | 290 | reg |= mii_advertise_flowctrl(efx->wanted_fc); |
306 | reg |= mii_advertise_flowctrl(efx->wanted_fc); | 291 | efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); |
307 | efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); | 292 | |
308 | 293 | /* Set up the (extended) next page if necessary */ | |
309 | /* Set up the (extended) next page if necessary */ | 294 | if (efx->phy_op->set_npage_adv) |
310 | if (efx->phy_op->set_npage_adv) | 295 | efx->phy_op->set_npage_adv(efx, ecmd->advertising); |
311 | efx->phy_op->set_npage_adv(efx, ecmd->advertising); | 296 | |
312 | 297 | /* Enable and restart AN */ | |
313 | /* Enable and restart AN */ | 298 | reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); |
314 | reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); | 299 | reg |= MDIO_AN_CTRL1_ENABLE; |
315 | reg |= MDIO_AN_CTRL1_ENABLE; | 300 | if (!(EFX_WORKAROUND_15195(efx) && |
316 | if (!(EFX_WORKAROUND_15195(efx) && | 301 | LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)) |
317 | LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)) | 302 | reg |= MDIO_AN_CTRL1_RESTART; |
318 | reg |= MDIO_AN_CTRL1_RESTART; | 303 | if (xnp) |
319 | if (xnp) | 304 | reg |= MDIO_AN_CTRL1_XNP; |
320 | reg |= MDIO_AN_CTRL1_XNP; | 305 | else |
321 | else | 306 | reg &= ~MDIO_AN_CTRL1_XNP; |
322 | reg &= ~MDIO_AN_CTRL1_XNP; | 307 | efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); |
323 | efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); | ||
324 | } else { | ||
325 | /* Disable AN */ | ||
326 | efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_CTRL1, | ||
327 | MDIO_AN_CTRL1_ENABLE, false); | ||
328 | |||
329 | /* Set the basic control bits */ | ||
330 | reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1); | ||
331 | reg &= ~(MDIO_CTRL1_SPEEDSEL | MDIO_CTRL1_FULLDPLX); | ||
332 | if (ecmd->speed == SPEED_100) | ||
333 | reg |= MDIO_PMA_CTRL1_SPEED100; | ||
334 | if (ecmd->duplex) | ||
335 | reg |= MDIO_CTRL1_FULLDPLX; | ||
336 | efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1, reg); | ||
337 | } | ||
338 | 308 | ||
339 | return 0; | 309 | return 0; |
340 | } | 310 | } |