diff options
Diffstat (limited to 'drivers/net/sfc/mdio_10g.c')
-rw-r--r-- | drivers/net/sfc/mdio_10g.c | 191 |
1 files changed, 89 insertions, 102 deletions
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index f6a16428113d..f9e2f95c3b48 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include "net_driver.h" | 15 | #include "net_driver.h" |
16 | #include "mdio_10g.h" | 16 | #include "mdio_10g.h" |
17 | #include "boards.h" | 17 | #include "boards.h" |
18 | #include "workarounds.h" | ||
18 | 19 | ||
19 | int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd, | 20 | int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd, |
20 | int spins, int spintime) | 21 | int spins, int spintime) |
@@ -179,17 +180,12 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) | |||
179 | return false; | 180 | return false; |
180 | else if (efx_phy_mode_disabled(efx->phy_mode)) | 181 | else if (efx_phy_mode_disabled(efx->phy_mode)) |
181 | return false; | 182 | return false; |
182 | else if (efx->loopback_mode == LOOPBACK_PHYXS) { | 183 | else if (efx->loopback_mode == LOOPBACK_PHYXS) |
183 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS | | 184 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS | |
184 | MDIO_MMDREG_DEVS_PCS | | 185 | MDIO_MMDREG_DEVS_PCS | |
185 | MDIO_MMDREG_DEVS_PMAPMD | | 186 | MDIO_MMDREG_DEVS_PMAPMD | |
186 | MDIO_MMDREG_DEVS_AN); | 187 | MDIO_MMDREG_DEVS_AN); |
187 | if (!mmd_mask) { | 188 | else if (efx->loopback_mode == LOOPBACK_PCS) |
188 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, | ||
189 | MDIO_PHYXS_STATUS2); | ||
190 | return !(reg & (1 << MDIO_PHYXS_STATUS2_RX_FAULT_LBN)); | ||
191 | } | ||
192 | } else if (efx->loopback_mode == LOOPBACK_PCS) | ||
193 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS | | 189 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS | |
194 | MDIO_MMDREG_DEVS_PMAPMD | | 190 | MDIO_MMDREG_DEVS_PMAPMD | |
195 | MDIO_MMDREG_DEVS_AN); | 191 | MDIO_MMDREG_DEVS_AN); |
@@ -197,6 +193,13 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) | |||
197 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PMAPMD | | 193 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PMAPMD | |
198 | MDIO_MMDREG_DEVS_AN); | 194 | MDIO_MMDREG_DEVS_AN); |
199 | 195 | ||
196 | if (!mmd_mask) { | ||
197 | /* Use presence of XGMII faults in leui of link state */ | ||
198 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, | ||
199 | MDIO_PHYXS_STATUS2); | ||
200 | return !(reg & (1 << MDIO_PHYXS_STATUS2_RX_FAULT_LBN)); | ||
201 | } | ||
202 | |||
200 | while (mmd_mask) { | 203 | while (mmd_mask) { |
201 | if (mmd_mask & 1) { | 204 | if (mmd_mask & 1) { |
202 | /* Double reads because link state is latched, and a | 205 | /* Double reads because link state is latched, and a |
@@ -263,7 +266,7 @@ void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, | |||
263 | } | 266 | } |
264 | } | 267 | } |
265 | 268 | ||
266 | 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) |
267 | { | 270 | { |
268 | int phy_id = efx->mii.phy_id; | 271 | int phy_id = efx->mii.phy_id; |
269 | u32 result = 0; | 272 | u32 result = 0; |
@@ -278,9 +281,6 @@ static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp) | |||
278 | result |= ADVERTISED_100baseT_Half; | 281 | result |= ADVERTISED_100baseT_Half; |
279 | if (reg & ADVERTISE_100FULL) | 282 | if (reg & ADVERTISE_100FULL) |
280 | result |= ADVERTISED_100baseT_Full; | 283 | result |= ADVERTISED_100baseT_Full; |
281 | if (reg & LPA_RESV) | ||
282 | result |= xnp; | ||
283 | |||
284 | return result; | 284 | return result; |
285 | } | 285 | } |
286 | 286 | ||
@@ -310,7 +310,7 @@ void mdio_clause45_get_settings(struct efx_nic *efx, | |||
310 | */ | 310 | */ |
311 | void mdio_clause45_get_settings_ext(struct efx_nic *efx, | 311 | void mdio_clause45_get_settings_ext(struct efx_nic *efx, |
312 | struct ethtool_cmd *ecmd, | 312 | struct ethtool_cmd *ecmd, |
313 | u32 xnp, u32 xnp_lpa) | 313 | u32 npage_adv, u32 npage_lpa) |
314 | { | 314 | { |
315 | int phy_id = efx->mii.phy_id; | 315 | int phy_id = efx->mii.phy_id; |
316 | int reg; | 316 | int reg; |
@@ -361,8 +361,8 @@ void mdio_clause45_get_settings_ext(struct efx_nic *efx, | |||
361 | ecmd->autoneg = AUTONEG_ENABLE; | 361 | ecmd->autoneg = AUTONEG_ENABLE; |
362 | ecmd->advertising |= | 362 | ecmd->advertising |= |
363 | ADVERTISED_Autoneg | | 363 | ADVERTISED_Autoneg | |
364 | mdio_clause45_get_an(efx, | 364 | mdio_clause45_get_an(efx, MDIO_AN_ADVERTISE) | |
365 | MDIO_AN_ADVERTISE, xnp); | 365 | npage_adv; |
366 | } else | 366 | } else |
367 | ecmd->autoneg = AUTONEG_DISABLE; | 367 | ecmd->autoneg = AUTONEG_DISABLE; |
368 | } else | 368 | } else |
@@ -371,27 +371,30 @@ void mdio_clause45_get_settings_ext(struct efx_nic *efx, | |||
371 | if (ecmd->autoneg) { | 371 | if (ecmd->autoneg) { |
372 | /* If AN is complete, report best common mode, | 372 | /* If AN is complete, report best common mode, |
373 | * otherwise report best advertised mode. */ | 373 | * otherwise report best advertised mode. */ |
374 | u32 common = ecmd->advertising; | 374 | u32 modes = 0; |
375 | if (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | 375 | if (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, |
376 | MDIO_MMDREG_STAT1) & | 376 | MDIO_MMDREG_STAT1) & |
377 | (1 << MDIO_AN_STATUS_AN_DONE_LBN)) { | 377 | (1 << MDIO_AN_STATUS_AN_DONE_LBN)) |
378 | common &= mdio_clause45_get_an(efx, MDIO_AN_LPA, | 378 | modes = (ecmd->advertising & |
379 | xnp_lpa); | 379 | (mdio_clause45_get_an(efx, MDIO_AN_LPA) | |
380 | } | 380 | npage_lpa)); |
381 | if (common & ADVERTISED_10000baseT_Full) { | 381 | if (modes == 0) |
382 | modes = ecmd->advertising; | ||
383 | |||
384 | if (modes & ADVERTISED_10000baseT_Full) { | ||
382 | ecmd->speed = SPEED_10000; | 385 | ecmd->speed = SPEED_10000; |
383 | ecmd->duplex = DUPLEX_FULL; | 386 | ecmd->duplex = DUPLEX_FULL; |
384 | } else if (common & (ADVERTISED_1000baseT_Full | | 387 | } else if (modes & (ADVERTISED_1000baseT_Full | |
385 | ADVERTISED_1000baseT_Half)) { | 388 | ADVERTISED_1000baseT_Half)) { |
386 | ecmd->speed = SPEED_1000; | 389 | ecmd->speed = SPEED_1000; |
387 | ecmd->duplex = !!(common & ADVERTISED_1000baseT_Full); | 390 | ecmd->duplex = !!(modes & ADVERTISED_1000baseT_Full); |
388 | } else if (common & (ADVERTISED_100baseT_Full | | 391 | } else if (modes & (ADVERTISED_100baseT_Full | |
389 | ADVERTISED_100baseT_Half)) { | 392 | ADVERTISED_100baseT_Half)) { |
390 | ecmd->speed = SPEED_100; | 393 | ecmd->speed = SPEED_100; |
391 | ecmd->duplex = !!(common & ADVERTISED_100baseT_Full); | 394 | ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full); |
392 | } else { | 395 | } else { |
393 | ecmd->speed = SPEED_10; | 396 | ecmd->speed = SPEED_10; |
394 | ecmd->duplex = !!(common & ADVERTISED_10baseT_Full); | 397 | ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full); |
395 | } | 398 | } |
396 | } else { | 399 | } else { |
397 | /* Report forced settings */ | 400 | /* Report forced settings */ |
@@ -415,7 +418,7 @@ int mdio_clause45_set_settings(struct efx_nic *efx, | |||
415 | int phy_id = efx->mii.phy_id; | 418 | int phy_id = efx->mii.phy_id; |
416 | struct ethtool_cmd prev; | 419 | struct ethtool_cmd prev; |
417 | u32 required; | 420 | u32 required; |
418 | int ctrl1_bits, reg; | 421 | int reg; |
419 | 422 | ||
420 | efx->phy_op->get_settings(efx, &prev); | 423 | efx->phy_op->get_settings(efx, &prev); |
421 | 424 | ||
@@ -430,99 +433,83 @@ int mdio_clause45_set_settings(struct efx_nic *efx, | |||
430 | if (prev.port != PORT_TP || ecmd->port != PORT_TP) | 433 | if (prev.port != PORT_TP || ecmd->port != PORT_TP) |
431 | return -EINVAL; | 434 | return -EINVAL; |
432 | 435 | ||
433 | /* Check that PHY supports these settings and work out the | 436 | /* Check that PHY supports these settings */ |
434 | * basic control bits */ | 437 | if (ecmd->autoneg) { |
435 | if (ecmd->duplex) { | 438 | required = SUPPORTED_Autoneg; |
439 | } else if (ecmd->duplex) { | ||
436 | switch (ecmd->speed) { | 440 | switch (ecmd->speed) { |
437 | case SPEED_10: | 441 | case SPEED_10: required = SUPPORTED_10baseT_Full; break; |
438 | ctrl1_bits = BMCR_FULLDPLX; | 442 | case SPEED_100: required = SUPPORTED_100baseT_Full; break; |
439 | required = SUPPORTED_10baseT_Full; | 443 | default: return -EINVAL; |
440 | break; | ||
441 | case SPEED_100: | ||
442 | ctrl1_bits = BMCR_SPEED100 | BMCR_FULLDPLX; | ||
443 | required = SUPPORTED_100baseT_Full; | ||
444 | break; | ||
445 | case SPEED_1000: | ||
446 | ctrl1_bits = BMCR_SPEED1000 | BMCR_FULLDPLX; | ||
447 | required = SUPPORTED_1000baseT_Full; | ||
448 | break; | ||
449 | case SPEED_10000: | ||
450 | ctrl1_bits = (BMCR_SPEED1000 | BMCR_SPEED100 | | ||
451 | BMCR_FULLDPLX); | ||
452 | required = SUPPORTED_10000baseT_Full; | ||
453 | break; | ||
454 | default: | ||
455 | return -EINVAL; | ||
456 | } | 444 | } |
457 | } else { | 445 | } else { |
458 | switch (ecmd->speed) { | 446 | switch (ecmd->speed) { |
459 | case SPEED_10: | 447 | case SPEED_10: required = SUPPORTED_10baseT_Half; break; |
460 | ctrl1_bits = 0; | 448 | case SPEED_100: required = SUPPORTED_100baseT_Half; break; |
461 | required = SUPPORTED_10baseT_Half; | 449 | default: return -EINVAL; |
462 | break; | ||
463 | case SPEED_100: | ||
464 | ctrl1_bits = BMCR_SPEED100; | ||
465 | required = SUPPORTED_100baseT_Half; | ||
466 | break; | ||
467 | case SPEED_1000: | ||
468 | ctrl1_bits = BMCR_SPEED1000; | ||
469 | required = SUPPORTED_1000baseT_Half; | ||
470 | break; | ||
471 | default: | ||
472 | return -EINVAL; | ||
473 | } | 450 | } |
474 | } | 451 | } |
475 | if (ecmd->autoneg) | ||
476 | required |= SUPPORTED_Autoneg; | ||
477 | required |= ecmd->advertising; | 452 | required |= ecmd->advertising; |
478 | if (required & ~prev.supported) | 453 | if (required & ~prev.supported) |
479 | return -EINVAL; | 454 | return -EINVAL; |
480 | 455 | ||
481 | /* Set the basic control bits */ | 456 | if (ecmd->autoneg) { |
482 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, | 457 | bool xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full |
483 | MDIO_MMDREG_CTRL1); | 458 | || EFX_WORKAROUND_13204(efx)); |
484 | reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX | 0x003c); | 459 | |
485 | reg |= ctrl1_bits; | 460 | /* Set up the base page */ |
486 | mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL1, | 461 | reg = ADVERTISE_CSMA; |
487 | reg); | 462 | if (ecmd->advertising & ADVERTISED_10baseT_Half) |
488 | 463 | reg |= ADVERTISE_10HALF; | |
489 | /* Set the AN registers */ | 464 | if (ecmd->advertising & ADVERTISED_10baseT_Full) |
490 | if (ecmd->autoneg != prev.autoneg || | 465 | reg |= ADVERTISE_10FULL; |
491 | ecmd->advertising != prev.advertising) { | 466 | if (ecmd->advertising & ADVERTISED_100baseT_Half) |
492 | bool xnp = false; | 467 | reg |= ADVERTISE_100HALF; |
493 | 468 | if (ecmd->advertising & ADVERTISED_100baseT_Full) | |
494 | if (efx->phy_op->set_xnp_advertise) | 469 | reg |= ADVERTISE_100FULL; |
495 | xnp = efx->phy_op->set_xnp_advertise(efx, | 470 | if (xnp) |
496 | ecmd->advertising); | 471 | reg |= ADVERTISE_RESV; |
497 | 472 | else if (ecmd->advertising & (ADVERTISED_1000baseT_Half | | |
498 | if (ecmd->autoneg) { | 473 | ADVERTISED_1000baseT_Full)) |
499 | reg = 0; | 474 | reg |= ADVERTISE_NPAGE; |
500 | if (ecmd->advertising & ADVERTISED_10baseT_Half) | 475 | reg |= efx_fc_advertise(efx->wanted_fc); |
501 | reg |= ADVERTISE_10HALF; | 476 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, |
502 | if (ecmd->advertising & ADVERTISED_10baseT_Full) | 477 | MDIO_AN_ADVERTISE, reg); |
503 | reg |= ADVERTISE_10FULL; | 478 | |
504 | if (ecmd->advertising & ADVERTISED_100baseT_Half) | 479 | /* Set up the (extended) next page if necessary */ |
505 | reg |= ADVERTISE_100HALF; | 480 | if (efx->phy_op->set_npage_adv) |
506 | if (ecmd->advertising & ADVERTISED_100baseT_Full) | 481 | efx->phy_op->set_npage_adv(efx, ecmd->advertising); |
507 | reg |= ADVERTISE_100FULL; | ||
508 | if (xnp) | ||
509 | reg |= ADVERTISE_RESV; | ||
510 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | ||
511 | MDIO_AN_ADVERTISE, reg); | ||
512 | } | ||
513 | 482 | ||
483 | /* Enable and restart AN */ | ||
514 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | 484 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, |
515 | MDIO_MMDREG_CTRL1); | 485 | MDIO_MMDREG_CTRL1); |
516 | if (ecmd->autoneg) | 486 | reg |= BMCR_ANENABLE; |
517 | reg |= BMCR_ANENABLE | BMCR_ANRESTART; | 487 | if (!(EFX_WORKAROUND_15195(efx) && |
518 | else | 488 | LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)) |
519 | reg &= ~BMCR_ANENABLE; | 489 | reg |= BMCR_ANRESTART; |
520 | if (xnp) | 490 | if (xnp) |
521 | reg |= 1 << MDIO_AN_CTRL_XNP_LBN; | 491 | reg |= 1 << MDIO_AN_CTRL_XNP_LBN; |
522 | else | 492 | else |
523 | reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN); | 493 | reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN); |
524 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | 494 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, |
525 | 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); | ||
526 | } | 513 | } |
527 | 514 | ||
528 | return 0; | 515 | return 0; |