aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/sfc/mdio_10g.c108
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,
248int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) 248int 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}