[PATCH net 1/1] RFC: drivers/net/phy: Fix for a BCM5482S auto-negotion problem
From: Corey Ashford <hidden>
Date: 2013-09-07 21:04:52
Subsystem:
broadcom ethernet phy drivers, ethernet phy library, networking drivers, the rest · Maintainers:
Florian Fainelli, Andrew Lunn, Heiner Kallweit, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
When a 1Gb network interface is used in SGMII mode off, and then a Broadcom 5482S is used to redrive SGMII (SGMII to SGMII mode) to a Broadcom 54616 PHY, the standard PHY registers do not appear to be updated correctly after auto-negotiation. This causes the kernel to get confused about the state of the link and also causes the MAC layer driver to inappropriately configure the MAC. By 'standard' registers I mean those that are read by genphy_read_link (MII_BMSR, 0x01) and genphy_read_status (MII_STAT1000, 0x0a; MII_CTRL1000, 0x09; MII_LPA, 0x05). Here are the register dumps for the various configurations: SGMII-to-SGMII mode, 1Gb, full duplex: # /var/dump1GPhy Shadow register '11111'=0x00007E5C Dumping registers for PHY at port e: PHY register 0=0x00001140 PHY register 1=0x00007949 PHY register 2=0x00000143 PHY register 3=0x0000BCB2 PHY register 4=0x000001E1 PHY register 5=0x00000000 PHY register 6=0x00000064 PHY register 7=0x00002001 PHY register 8=0x00000000 PHY register 9=0x00000200 PHY register A=0x00000000 PHY register B=0x00000000 PHY register C=0x00000000 PHY register D=0x00000000 PHY register E=0x00000000 PHY register F=0x00003000 PHY register 10=0x00001000 PHY register 11=0x00002000 PHY register 12=0x00000000 PHY register 13=0x00000C00 PHY register 14=0x00000000 PHY register 15=0x00000000 PHY register 16=0x00000000 PHY register 17=0x00000000 PHY register 18=0x00000400 PHY register 19=0x00001000 PHY register 1A=0x00000000 PHY register 1B=0x0000FFF1 PHY register 1C=0x00007E5C PHY register 1D=0x00000000 PHY register 1E=0x00000000 PHY register 1F=0x00000000 PHY expansion register E00=0x00001140 PHY expansion register E01=0x0000016D PHY expansion register E02=0x00000143 PHY expansion register E03=0x0000BCB2 PHY expansion register E04=0x00000001 PHY expansion register E05=0x0000D801 PHY expansion register E06=0x00000064 PHY expansion register E07=0x00002001 PHY expansion register E08=0x00000000 PHY expansion register E09=0x00000000 PHY expansion register E0A=0x00000000 PHY expansion register E0B=0x00000000 PHY expansion register E0C=0x00000000 PHY expansion register E0D=0x00000000 PHY expansion register E0E=0x00000000 PHY expansion register E0F=0x0000C000 PHY expansion register E10=0x00000000 PHY expansion register E11=0x00000000 PHY expansion register E12=0x00000080 PHY expansion register E13=0x00000089 PHY expansion register E14=0x00000000 PHY expansion register E15=0x0000038A PHY expansion register E16=0x0000002E Mode status register = 0x0000D072 Successfully completed! SGMII-to-SGMII mode, 100Mb, half duplex: # /var/dump1GPhy Shadow register '11111'=0x00007E5C Dumping registers for PHY at port e: PHY register 0=0x00001140 PHY register 1=0x00007949 PHY register 2=0x00000143 PHY register 3=0x0000BCB2 PHY register 4=0x000001E1 PHY register 5=0x00000000 PHY register 6=0x00000064 PHY register 7=0x00002001 PHY register 8=0x00000000 PHY register 9=0x00000200 PHY register A=0x00000000 PHY register B=0x00000000 PHY register C=0x00000000 PHY register D=0x00000000 PHY register E=0x00000000 PHY register F=0x00003000 PHY register 10=0x00001000 PHY register 11=0x00002000 PHY register 12=0x00000000 PHY register 13=0x00000C00 PHY register 14=0x00000000 PHY register 15=0x00000000 PHY register 16=0x00000000 PHY register 17=0x00000000 PHY register 18=0x00000400 PHY register 19=0x00001000 PHY register 1A=0x00000000 PHY register 1B=0x0000FFF1 PHY register 1C=0x00007E5C PHY register 1D=0x00000000 PHY register 1E=0x00000000 PHY register 1F=0x00000000 PHY expansion register E00=0x00001140 PHY expansion register E01=0x00000169 PHY expansion register E02=0x00000143 PHY expansion register E03=0x0000BCB2 PHY expansion register E04=0x00000001 PHY expansion register E05=0x0000C401 PHY expansion register E06=0x00000066 PHY expansion register E07=0x00002001 PHY expansion register E08=0x00000000 PHY expansion register E09=0x00000000 PHY expansion register E0A=0x00000000 PHY expansion register E0B=0x00000000 PHY expansion register E0C=0x00000000 PHY expansion register E0D=0x00000000 PHY expansion register E0E=0x00000000 PHY expansion register E0F=0x0000C000 PHY expansion register E10=0x00000000 PHY expansion register E11=0x00000000 PHY expansion register E12=0x00000080 PHY expansion register E13=0x00000058 PHY expansion register E14=0x00000000 PHY expansion register E15=0x0000026A PHY expansion register E16=0x0000002E Mode status register = 0x0000A072 Successfully completed! SGMII-to-serdes, 1Gb, full duplex: # /var/dump1GPhy Shadow register '11111'=0x00007E5C Dumping registers for PHY at port e: PHY register 0=0x00001140 PHY register 1=0x00007949 PHY register 2=0x00000143 PHY register 3=0x0000BCB2 PHY register 4=0x000001E1 PHY register 5=0x00000000 PHY register 6=0x00000064 PHY register 7=0x00002001 PHY register 8=0x00000000 PHY register 9=0x00000200 PHY register A=0x00000000 PHY register B=0x00000000 PHY register C=0x00000000 PHY register D=0x00000000 PHY register E=0x00000000 PHY register F=0x00003000 PHY register 10=0x00001000 PHY register 11=0x00000000 PHY register 12=0x00000000 PHY register 13=0x00000C00 PHY register 14=0x00000000 PHY register 15=0x0000D072 PHY register 16=0x00000000 PHY register 17=0x00000F42 PHY register 18=0x00000400 PHY register 19=0x00001000 PHY register 1A=0x00000000 PHY register 1B=0x0000FFF1 PHY register 1C=0x00007E5C PHY register 1D=0x00000000 PHY register 1E=0x00000000 PHY register 1F=0x00000000 PHY expansion register E00=0x00001140 PHY expansion register E01=0x0000014D PHY expansion register E02=0x00000143 PHY expansion register E03=0x0000BCB2 PHY expansion register E04=0x00000060 PHY expansion register E05=0x00000000 PHY expansion register E06=0x00000064 PHY expansion register E07=0x00002001 PHY expansion register E08=0x00000000 PHY expansion register E09=0x00000000 PHY expansion register E0A=0x00000000 PHY expansion register E0B=0x00000000 PHY expansion register E0C=0x00000000 PHY expansion register E0D=0x00000000 PHY expansion register E0E=0x00000000 PHY expansion register E0F=0x0000C000 PHY expansion register E10=0x00000000 PHY expansion register E11=0x00000000 PHY expansion register E12=0x00000080 PHY expansion register E13=0x000002D3 PHY expansion register E14=0x00000000 PHY expansion register E15=0x00000388 PHY expansion register E16=0x0000002E Mode status register = 0x0000D072 Successfully completed! Signed-off-by: Corey Ashford <redacted> --- drivers/net/phy/broadcom.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-)
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index f8c90ea..9f5d076 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c@@ -142,6 +142,13 @@ #define MII_BCM54XX_EXP_EXP96_MYST 0x0010 #define MII_BCM54XX_EXP_EXP97 0x0f97 #define MII_BCM54XX_EXP_EXP97_MYST 0x0c0c +#define MII_BCM54XX_EXP_OPER_MODE (MII_BCM54XX_EXP_SEL_ER | 0x42) +#define MII_BCM54XX_EXP_OPER_MODE_SERDES_LINK 0x8000 +#define MII_BCM54XX_EXP_OPER_MODE_SERDES_SPEED_MASK 0x6000 +#define MII_BCM54XX_EXP_OPER_MODE_SERDES_SPEED_1000 0x4000 +#define MII_BCM54XX_EXP_OPER_MODE_SERDES_SPEED_100 0x2000 +#define MII_BCM54XX_EXP_OPER_MODE_SERDES_SPEED_10 0x0000 +#define MII_BCM54XX_EXP_OPER_MODE_SERDES_DUPLEX 0x1000 /* * BCM5482: Secondary SerDes registers
@@ -491,21 +498,31 @@ static int bcm5482_config_init(struct phy_device *phydev) static int bcm5482_read_status(struct phy_device *phydev) { int err; + err = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_OPER_MODE); + if (err < 0) + return err; - err = genphy_read_status(phydev); + phydev->link = ((err & MII_BCM54XX_EXP_OPER_MODE_SERDES_LINK) == + MII_BCM54XX_EXP_OPER_MODE_SERDES_LINK); - if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { - /* - * Only link status matters for 1000Base-X mode, so force - * 1000 Mbit/s full-duplex status - */ - if (phydev->link) { + if (phydev->link) { + switch (err & MII_BCM54XX_EXP_OPER_MODE_SERDES_SPEED_MASK) { + case MII_BCM54XX_EXP_OPER_MODE_SERDES_SPEED_1000: phydev->speed = SPEED_1000; - phydev->duplex = DUPLEX_FULL; + break; + case MII_BCM54XX_EXP_OPER_MODE_SERDES_SPEED_100: + phydev->speed = SPEED_100; + break; + default: + phydev->speed = SPEED_10; + break; } + if (err & MII_BCM54XX_EXP_OPER_MODE_SERDES_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; } - - return err; + return 0; } static int bcm54xx_ack_interrupt(struct phy_device *phydev)
--
1.8.1.4