Skip to content

Commit c84786f

Browse files
Russell Kingdavem330
authored andcommitted
net: phy: marvell10g: read copper results from CSSR1
Read the copper autonegotiation results from the copper specific status register, rather than decoding the advertisements. Reading what the link is actually doing will allow us to support downshift modes. Reviewed-by: Andrew Lunn <[email protected]> Signed-off-by: Russell King <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent be64e39 commit c84786f

File tree

1 file changed

+89
-52
lines changed

1 file changed

+89
-52
lines changed

drivers/net/phy/marvell10g.c

Lines changed: 89 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,19 @@ enum {
3939
MV_PCS_BASE_R = 0x1000,
4040
MV_PCS_1000BASEX = 0x2000,
4141

42-
MV_PCS_PAIRSWAP = 0x8182,
43-
MV_PCS_PAIRSWAP_MASK = 0x0003,
44-
MV_PCS_PAIRSWAP_AB = 0x0002,
45-
MV_PCS_PAIRSWAP_NONE = 0x0003,
42+
MV_PCS_CSSR1 = 0x8008,
43+
MV_PCS_CSSR1_SPD1_MASK = 0xc000,
44+
MV_PCS_CSSR1_SPD1_SPD2 = 0xc000,
45+
MV_PCS_CSSR1_SPD1_1000 = 0x8000,
46+
MV_PCS_CSSR1_SPD1_100 = 0x4000,
47+
MV_PCS_CSSR1_SPD1_10 = 0x0000,
48+
MV_PCS_CSSR1_DUPLEX_FULL= BIT(13),
49+
MV_PCS_CSSR1_RESOLVED = BIT(11),
50+
MV_PCS_CSSR1_MDIX = BIT(6),
51+
MV_PCS_CSSR1_SPD2_MASK = 0x000c,
52+
MV_PCS_CSSR1_SPD2_5000 = 0x0008,
53+
MV_PCS_CSSR1_SPD2_2500 = 0x0004,
54+
MV_PCS_CSSR1_SPD2_10000 = 0x0000,
4655

4756
/* These registers appear at 0x800X and 0xa00X - the 0xa00X control
4857
* registers appear to set themselves to the 0x800X when AN is
@@ -413,35 +422,18 @@ static void mv3310_update_interface(struct phy_device *phydev)
413422
}
414423

415424
/* 10GBASE-ER,LR,LRM,SR do not support autonegotiation. */
416-
static int mv3310_read_10gbr_status(struct phy_device *phydev)
425+
static int mv3310_read_status_10gbaser(struct phy_device *phydev)
417426
{
418427
phydev->link = 1;
419428
phydev->speed = SPEED_10000;
420429
phydev->duplex = DUPLEX_FULL;
421430

422-
mv3310_update_interface(phydev);
423-
424431
return 0;
425432
}
426433

427-
static int mv3310_read_status(struct phy_device *phydev)
434+
static int mv3310_read_status_copper(struct phy_device *phydev)
428435
{
429-
int val;
430-
431-
phydev->speed = SPEED_UNKNOWN;
432-
phydev->duplex = DUPLEX_UNKNOWN;
433-
linkmode_zero(phydev->lp_advertising);
434-
phydev->link = 0;
435-
phydev->pause = 0;
436-
phydev->asym_pause = 0;
437-
phydev->mdix = 0;
438-
439-
val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1);
440-
if (val < 0)
441-
return val;
442-
443-
if (val & MDIO_STAT1_LSTATUS)
444-
return mv3310_read_10gbr_status(phydev);
436+
int cssr1, speed, val;
445437

446438
val = genphy_c45_read_link(phydev);
447439
if (val < 0)
@@ -451,6 +443,52 @@ static int mv3310_read_status(struct phy_device *phydev)
451443
if (val < 0)
452444
return val;
453445

446+
cssr1 = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_CSSR1);
447+
if (cssr1 < 0)
448+
return val;
449+
450+
/* If the link settings are not resolved, mark the link down */
451+
if (!(cssr1 & MV_PCS_CSSR1_RESOLVED)) {
452+
phydev->link = 0;
453+
return 0;
454+
}
455+
456+
/* Read the copper link settings */
457+
speed = cssr1 & MV_PCS_CSSR1_SPD1_MASK;
458+
if (speed == MV_PCS_CSSR1_SPD1_SPD2)
459+
speed |= cssr1 & MV_PCS_CSSR1_SPD2_MASK;
460+
461+
switch (speed) {
462+
case MV_PCS_CSSR1_SPD1_SPD2 | MV_PCS_CSSR1_SPD2_10000:
463+
phydev->speed = SPEED_10000;
464+
break;
465+
466+
case MV_PCS_CSSR1_SPD1_SPD2 | MV_PCS_CSSR1_SPD2_5000:
467+
phydev->speed = SPEED_5000;
468+
break;
469+
470+
case MV_PCS_CSSR1_SPD1_SPD2 | MV_PCS_CSSR1_SPD2_2500:
471+
phydev->speed = SPEED_2500;
472+
break;
473+
474+
case MV_PCS_CSSR1_SPD1_1000:
475+
phydev->speed = SPEED_1000;
476+
break;
477+
478+
case MV_PCS_CSSR1_SPD1_100:
479+
phydev->speed = SPEED_100;
480+
break;
481+
482+
case MV_PCS_CSSR1_SPD1_10:
483+
phydev->speed = SPEED_10;
484+
break;
485+
}
486+
487+
phydev->duplex = cssr1 & MV_PCS_CSSR1_DUPLEX_FULL ?
488+
DUPLEX_FULL : DUPLEX_HALF;
489+
phydev->mdix = cssr1 & MV_PCS_CSSR1_MDIX ?
490+
ETH_TP_MDI_X : ETH_TP_MDI;
491+
454492
if (val & MDIO_AN_STAT1_COMPLETE) {
455493
val = genphy_c45_read_lpa(phydev);
456494
if (val < 0)
@@ -463,39 +501,38 @@ static int mv3310_read_status(struct phy_device *phydev)
463501

464502
mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
465503

466-
if (phydev->autoneg == AUTONEG_ENABLE)
467-
phy_resolve_aneg_linkmode(phydev);
504+
/* Update the pause status */
505+
phy_resolve_aneg_pause(phydev);
468506
}
469507

470-
if (phydev->autoneg != AUTONEG_ENABLE) {
471-
val = genphy_c45_read_pma(phydev);
472-
if (val < 0)
473-
return val;
474-
}
508+
return 0;
509+
}
475510

476-
if (phydev->speed == SPEED_10000) {
477-
val = genphy_c45_read_mdix(phydev);
478-
if (val < 0)
479-
return val;
480-
} else {
481-
val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_PAIRSWAP);
482-
if (val < 0)
483-
return val;
511+
static int mv3310_read_status(struct phy_device *phydev)
512+
{
513+
int err, val;
484514

485-
switch (val & MV_PCS_PAIRSWAP_MASK) {
486-
case MV_PCS_PAIRSWAP_AB:
487-
phydev->mdix = ETH_TP_MDI_X;
488-
break;
489-
case MV_PCS_PAIRSWAP_NONE:
490-
phydev->mdix = ETH_TP_MDI;
491-
break;
492-
default:
493-
phydev->mdix = ETH_TP_MDI_INVALID;
494-
break;
495-
}
496-
}
515+
phydev->speed = SPEED_UNKNOWN;
516+
phydev->duplex = DUPLEX_UNKNOWN;
517+
linkmode_zero(phydev->lp_advertising);
518+
phydev->link = 0;
519+
phydev->pause = 0;
520+
phydev->asym_pause = 0;
521+
phydev->mdix = ETH_TP_MDI_INVALID;
497522

498-
mv3310_update_interface(phydev);
523+
val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1);
524+
if (val < 0)
525+
return val;
526+
527+
if (val & MDIO_STAT1_LSTATUS)
528+
err = mv3310_read_status_10gbaser(phydev);
529+
else
530+
err = mv3310_read_status_copper(phydev);
531+
if (err < 0)
532+
return err;
533+
534+
if (phydev->link)
535+
mv3310_update_interface(phydev);
499536

500537
return 0;
501538
}

0 commit comments

Comments
 (0)