aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc/mdio_10g.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sfc/mdio_10g.c')
-rw-r--r--drivers/net/sfc/mdio_10g.c177
1 files changed, 79 insertions, 98 deletions
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 16bc5853d0ea..f9e2f95c3b48 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -266,7 +266,7 @@ void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
266 } 266 }
267} 267}
268 268
269static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp) 269static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr)
270{ 270{
271 int phy_id = efx->mii.phy_id; 271 int phy_id = efx->mii.phy_id;
272 u32 result = 0; 272 u32 result = 0;
@@ -281,9 +281,6 @@ static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp)
281 result |= ADVERTISED_100baseT_Half; 281 result |= ADVERTISED_100baseT_Half;
282 if (reg & ADVERTISE_100FULL) 282 if (reg & ADVERTISE_100FULL)
283 result |= ADVERTISED_100baseT_Full; 283 result |= ADVERTISED_100baseT_Full;
284 if (reg & LPA_RESV)
285 result |= xnp;
286
287 return result; 284 return result;
288} 285}
289 286
@@ -313,7 +310,7 @@ void mdio_clause45_get_settings(struct efx_nic *efx,
313 */ 310 */
314void mdio_clause45_get_settings_ext(struct efx_nic *efx, 311void mdio_clause45_get_settings_ext(struct efx_nic *efx,
315 struct ethtool_cmd *ecmd, 312 struct ethtool_cmd *ecmd,
316 u32 xnp, u32 xnp_lpa) 313 u32 npage_adv, u32 npage_lpa)
317{ 314{
318 int phy_id = efx->mii.phy_id; 315 int phy_id = efx->mii.phy_id;
319 int reg; 316 int reg;
@@ -364,8 +361,8 @@ void mdio_clause45_get_settings_ext(struct efx_nic *efx,
364 ecmd->autoneg = AUTONEG_ENABLE; 361 ecmd->autoneg = AUTONEG_ENABLE;
365 ecmd->advertising |= 362 ecmd->advertising |=
366 ADVERTISED_Autoneg | 363 ADVERTISED_Autoneg |
367 mdio_clause45_get_an(efx, 364 mdio_clause45_get_an(efx, MDIO_AN_ADVERTISE) |
368 MDIO_AN_ADVERTISE, xnp); 365 npage_adv;
369 } else 366 } else
370 ecmd->autoneg = AUTONEG_DISABLE; 367 ecmd->autoneg = AUTONEG_DISABLE;
371 } else 368 } else
@@ -374,27 +371,30 @@ void mdio_clause45_get_settings_ext(struct efx_nic *efx,
374 if (ecmd->autoneg) { 371 if (ecmd->autoneg) {
375 /* If AN is complete, report best common mode, 372 /* If AN is complete, report best common mode,
376 * otherwise report best advertised mode. */ 373 * otherwise report best advertised mode. */
377 u32 common = ecmd->advertising; 374 u32 modes = 0;
378 if (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, 375 if (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
379 MDIO_MMDREG_STAT1) & 376 MDIO_MMDREG_STAT1) &
380 (1 << MDIO_AN_STATUS_AN_DONE_LBN)) { 377 (1 << MDIO_AN_STATUS_AN_DONE_LBN))
381 common &= mdio_clause45_get_an(efx, MDIO_AN_LPA, 378 modes = (ecmd->advertising &
382 xnp_lpa); 379 (mdio_clause45_get_an(efx, MDIO_AN_LPA) |
383 } 380 npage_lpa));
384 if (common & ADVERTISED_10000baseT_Full) { 381 if (modes == 0)
382 modes = ecmd->advertising;
383
384 if (modes & ADVERTISED_10000baseT_Full) {
385 ecmd->speed = SPEED_10000; 385 ecmd->speed = SPEED_10000;
386 ecmd->duplex = DUPLEX_FULL; 386 ecmd->duplex = DUPLEX_FULL;
387 } else if (common & (ADVERTISED_1000baseT_Full | 387 } else if (modes & (ADVERTISED_1000baseT_Full |
388 ADVERTISED_1000baseT_Half)) { 388 ADVERTISED_1000baseT_Half)) {
389 ecmd->speed = SPEED_1000; 389 ecmd->speed = SPEED_1000;
390 ecmd->duplex = !!(common & ADVERTISED_1000baseT_Full); 390 ecmd->duplex = !!(modes & ADVERTISED_1000baseT_Full);
391 } else if (common & (ADVERTISED_100baseT_Full | 391 } else if (modes & (ADVERTISED_100baseT_Full |
392 ADVERTISED_100baseT_Half)) { 392 ADVERTISED_100baseT_Half)) {
393 ecmd->speed = SPEED_100; 393 ecmd->speed = SPEED_100;
394 ecmd->duplex = !!(common & ADVERTISED_100baseT_Full); 394 ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full);
395 } else { 395 } else {
396 ecmd->speed = SPEED_10; 396 ecmd->speed = SPEED_10;
397 ecmd->duplex = !!(common & ADVERTISED_10baseT_Full); 397 ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full);
398 } 398 }
399 } else { 399 } else {
400 /* Report forced settings */ 400 /* Report forced settings */
@@ -418,7 +418,7 @@ int mdio_clause45_set_settings(struct efx_nic *efx,
418 int phy_id = efx->mii.phy_id; 418 int phy_id = efx->mii.phy_id;
419 struct ethtool_cmd prev; 419 struct ethtool_cmd prev;
420 u32 required; 420 u32 required;
421 int ctrl1_bits, reg; 421 int reg;
422 422
423 efx->phy_op->get_settings(efx, &prev); 423 efx->phy_op->get_settings(efx, &prev);
424 424
@@ -433,102 +433,83 @@ int mdio_clause45_set_settings(struct efx_nic *efx,
433 if (prev.port != PORT_TP || ecmd->port != PORT_TP) 433 if (prev.port != PORT_TP || ecmd->port != PORT_TP)
434 return -EINVAL; 434 return -EINVAL;
435 435
436 /* Check that PHY supports these settings and work out the 436 /* Check that PHY supports these settings */
437 * basic control bits */ 437 if (ecmd->autoneg) {
438 if (ecmd->duplex) { 438 required = SUPPORTED_Autoneg;
439 } else if (ecmd->duplex) {
439 switch (ecmd->speed) { 440 switch (ecmd->speed) {
440 case SPEED_10: 441 case SPEED_10: required = SUPPORTED_10baseT_Full; break;
441 ctrl1_bits = BMCR_FULLDPLX; 442 case SPEED_100: required = SUPPORTED_100baseT_Full; break;
442 required = SUPPORTED_10baseT_Full; 443 default: return -EINVAL;
443 break;
444 case SPEED_100:
445 ctrl1_bits = BMCR_SPEED100 | BMCR_FULLDPLX;
446 required = SUPPORTED_100baseT_Full;
447 break;
448 case SPEED_1000:
449 ctrl1_bits = BMCR_SPEED1000 | BMCR_FULLDPLX;
450 required = SUPPORTED_1000baseT_Full;
451 break;
452 case SPEED_10000:
453 ctrl1_bits = (BMCR_SPEED1000 | BMCR_SPEED100 |
454 BMCR_FULLDPLX);
455 required = SUPPORTED_10000baseT_Full;
456 break;
457 default:
458 return -EINVAL;
459 } 444 }
460 } else { 445 } else {
461 switch (ecmd->speed) { 446 switch (ecmd->speed) {
462 case SPEED_10: 447 case SPEED_10: required = SUPPORTED_10baseT_Half; break;
463 ctrl1_bits = 0; 448 case SPEED_100: required = SUPPORTED_100baseT_Half; break;
464 required = SUPPORTED_10baseT_Half; 449 default: return -EINVAL;
465 break;
466 case SPEED_100:
467 ctrl1_bits = BMCR_SPEED100;
468 required = SUPPORTED_100baseT_Half;
469 break;
470 case SPEED_1000:
471 ctrl1_bits = BMCR_SPEED1000;
472 required = SUPPORTED_1000baseT_Half;
473 break;
474 default:
475 return -EINVAL;
476 } 450 }
477 } 451 }
478 if (ecmd->autoneg)
479 required |= SUPPORTED_Autoneg;
480 required |= ecmd->advertising; 452 required |= ecmd->advertising;
481 if (required & ~prev.supported) 453 if (required & ~prev.supported)
482 return -EINVAL; 454 return -EINVAL;
483 455
484 /* Set the basic control bits */ 456 if (ecmd->autoneg) {
485 reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, 457 bool xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full
486 MDIO_MMDREG_CTRL1); 458 || EFX_WORKAROUND_13204(efx));
487 reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX | 0x003c); 459
488 reg |= ctrl1_bits; 460 /* Set up the base page */
489 mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL1, 461 reg = ADVERTISE_CSMA;
490 reg); 462 if (ecmd->advertising & ADVERTISED_10baseT_Half)
491 463 reg |= ADVERTISE_10HALF;
492 /* Set the AN registers */ 464 if (ecmd->advertising & ADVERTISED_10baseT_Full)
493 if (ecmd->autoneg != prev.autoneg || 465 reg |= ADVERTISE_10FULL;
494 ecmd->advertising != prev.advertising) { 466 if (ecmd->advertising & ADVERTISED_100baseT_Half)
495 bool xnp = false; 467 reg |= ADVERTISE_100HALF;
496 468 if (ecmd->advertising & ADVERTISED_100baseT_Full)
497 if (efx->phy_op->set_xnp_advertise) 469 reg |= ADVERTISE_100FULL;
498 xnp = efx->phy_op->set_xnp_advertise(efx, 470 if (xnp)
499 ecmd->advertising); 471 reg |= ADVERTISE_RESV;
500 472 else if (ecmd->advertising & (ADVERTISED_1000baseT_Half |
501 if (ecmd->autoneg) { 473 ADVERTISED_1000baseT_Full))
502 reg = 0; 474 reg |= ADVERTISE_NPAGE;
503 if (ecmd->advertising & ADVERTISED_10baseT_Half) 475 reg |= efx_fc_advertise(efx->wanted_fc);
504 reg |= ADVERTISE_10HALF; 476 mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
505 if (ecmd->advertising & ADVERTISED_10baseT_Full) 477 MDIO_AN_ADVERTISE, reg);
506 reg |= ADVERTISE_10FULL; 478
507 if (ecmd->advertising & ADVERTISED_100baseT_Half) 479 /* Set up the (extended) next page if necessary */
508 reg |= ADVERTISE_100HALF; 480 if (efx->phy_op->set_npage_adv)
509 if (ecmd->advertising & ADVERTISED_100baseT_Full) 481 efx->phy_op->set_npage_adv(efx, ecmd->advertising);
510 reg |= ADVERTISE_100FULL;
511 if (xnp)
512 reg |= ADVERTISE_RESV;
513 mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
514 MDIO_AN_ADVERTISE, reg);
515 }
516 482
483 /* Enable and restart AN */
517 reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, 484 reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
518 MDIO_MMDREG_CTRL1); 485 MDIO_MMDREG_CTRL1);
519 if (ecmd->autoneg) 486 reg |= BMCR_ANENABLE;
520 reg |= BMCR_ANENABLE | BMCR_ANRESTART; 487 if (!(EFX_WORKAROUND_15195(efx) &&
521 else 488 LOOPBACK_MASK(efx) & efx->phy_op->loopbacks))
522 reg &= ~BMCR_ANENABLE; 489 reg |= BMCR_ANRESTART;
523 if (EFX_WORKAROUND_15195(efx)
524 && LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)
525 reg &= ~BMCR_ANRESTART;
526 if (xnp) 490 if (xnp)
527 reg |= 1 << MDIO_AN_CTRL_XNP_LBN; 491 reg |= 1 << MDIO_AN_CTRL_XNP_LBN;
528 else 492 else
529 reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN); 493 reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN);
530 mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, 494 mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
531 MDIO_MMDREG_CTRL1, reg); 495 MDIO_MMDREG_CTRL1, reg);
496 } else {
497 /* Disable AN */
498 mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_AN,
499 MDIO_MMDREG_CTRL1,
500 __ffs(BMCR_ANENABLE), false);
501
502 /* Set the basic control bits */
503 reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
504 MDIO_MMDREG_CTRL1);
505 reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX |
506 0x003c);
507 if (ecmd->speed == SPEED_100)
508 reg |= BMCR_SPEED100;
509 if (ecmd->duplex)
510 reg |= BMCR_FULLDPLX;
511 mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
512 MDIO_MMDREG_CTRL1, reg);
532 } 513 }
533 514
534 return 0; 515 return 0;