diff options
Diffstat (limited to 'drivers/net/sfc/mdio_10g.c')
-rw-r--r-- | drivers/net/sfc/mdio_10g.c | 177 |
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 | ||
269 | static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp) | 269 | static 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 | */ |
314 | void mdio_clause45_get_settings_ext(struct efx_nic *efx, | 311 | void 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; |