| From foo@baz Sat 18 Apr 2020 11:06:47 AM CEST |
| From: Clemens Gruber <clemens.gruber@pqgruber.com> |
| Date: Sat, 11 Apr 2020 18:51:25 +0200 |
| Subject: net: phy: marvell: Fix pause frame negotiation |
| |
| From: Clemens Gruber <clemens.gruber@pqgruber.com> |
| |
| [ Upstream commit 3b72f84f8fb65e83e85e9be58eabcf95a40b8f46 ] |
| |
| The negotiation of flow control / pause frame modes was broken since |
| commit fcf1f59afc67 ("net: phy: marvell: rearrange to use |
| genphy_read_lpa()") moved the setting of phydev->duplex below the |
| phy_resolve_aneg_pause call. Due to a check of DUPLEX_FULL in that |
| function, phydev->pause was no longer set. |
| |
| Fix it by moving the parsing of the status variable before the blocks |
| dealing with the pause frames. |
| |
| As the Marvell 88E1510 datasheet does not specify the timing between the |
| link status and the "Speed and Duplex Resolved" bit, we have to force |
| the link down as long as the resolved bit is not set, to avoid reporting |
| link up before we even have valid Speed/Duplex. |
| |
| Tested with a Marvell 88E1510 (RGMII to Copper/1000Base-T) |
| |
| Fixes: fcf1f59afc67 ("net: phy: marvell: rearrange to use genphy_read_lpa()") |
| Signed-off-by: Clemens Gruber <clemens.gruber@pqgruber.com> |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/phy/marvell.c | 46 ++++++++++++++++++++++++---------------------- |
| 1 file changed, 24 insertions(+), 22 deletions(-) |
| |
| --- a/drivers/net/phy/marvell.c |
| +++ b/drivers/net/phy/marvell.c |
| @@ -1278,6 +1278,30 @@ static int marvell_read_status_page_an(s |
| int lpa; |
| int err; |
| |
| + if (!(status & MII_M1011_PHY_STATUS_RESOLVED)) { |
| + phydev->link = 0; |
| + return 0; |
| + } |
| + |
| + if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) |
| + phydev->duplex = DUPLEX_FULL; |
| + else |
| + phydev->duplex = DUPLEX_HALF; |
| + |
| + switch (status & MII_M1011_PHY_STATUS_SPD_MASK) { |
| + case MII_M1011_PHY_STATUS_1000: |
| + phydev->speed = SPEED_1000; |
| + break; |
| + |
| + case MII_M1011_PHY_STATUS_100: |
| + phydev->speed = SPEED_100; |
| + break; |
| + |
| + default: |
| + phydev->speed = SPEED_10; |
| + break; |
| + } |
| + |
| if (!fiber) { |
| err = genphy_read_lpa(phydev); |
| if (err < 0) |
| @@ -1306,28 +1330,6 @@ static int marvell_read_status_page_an(s |
| } |
| } |
| |
| - if (!(status & MII_M1011_PHY_STATUS_RESOLVED)) |
| - return 0; |
| - |
| - if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) |
| - phydev->duplex = DUPLEX_FULL; |
| - else |
| - phydev->duplex = DUPLEX_HALF; |
| - |
| - switch (status & MII_M1011_PHY_STATUS_SPD_MASK) { |
| - case MII_M1011_PHY_STATUS_1000: |
| - phydev->speed = SPEED_1000; |
| - break; |
| - |
| - case MII_M1011_PHY_STATUS_100: |
| - phydev->speed = SPEED_100; |
| - break; |
| - |
| - default: |
| - phydev->speed = SPEED_10; |
| - break; |
| - } |
| - |
| return 0; |
| } |
| |