summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAndrew Lunn <andrew@lunn.ch>2020-04-28 19:58:33 +0200
committerDavid S. Miller <davem@davemloft.net>2020-04-28 14:33:19 -0700
commit790ab249b55d75fdb427b92f81964cd7cb525eec (patch)
treea7a239a53b77d316964e1c08d848137cc314327a /drivers
parent88fb831f773e6c51ec528eacb524f00f518f7e54 (diff)
net: ethernet: fec: Prevent MII event after MII_SPEED write
The change to polled IO for MDIO completion assumes that MII events are only generated for MDIO transactions. However on some SoCs writing to the MII_SPEED register can also trigger an MII event. As a result, the next MDIO read has a pending MII event, and immediately reads the data registers before it contains useful data. When the read does complete, another MII event is posted, which results in the next read also going wrong, and the cycle continues. By writing 0 to the MII_DATA register before writing to the speed register, this MII event for the MII_SPEED is suppressed, and polled IO works as expected. Fixes: 29ae6bd1b0d8 ("net: ethernet: fec: Replace interrupt driven MDIO with polled IO") Reported-by: Andy Duan <fugang.duan@nxp.com> Suggested-by: Andy Duan <fugang.duan@nxp.com> Signed-off-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 1ae075a246a3..aa5e744ec098 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -996,6 +996,9 @@ fec_restart(struct net_device *ndev)
writel(0x0, fep->hwp + FEC_X_CNTRL);
}
+ /* Prevent an MII event being report when changing speed */
+ writel(0, fep->hwp + FEC_MII_DATA);
+
/* Set MII speed */
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
@@ -1182,6 +1185,10 @@ fec_stop(struct net_device *ndev)
writel(val, fep->hwp + FEC_ECNTRL);
fec_enet_stop_mode(fep, true);
}
+
+ /* Prevent an MII event being report when changing speed */
+ writel(0, fep->hwp + FEC_MII_DATA);
+
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
/* We have to keep ENET enabled to have MII interrupt stay working */
@@ -2142,6 +2149,16 @@ static int fec_enet_mii_init(struct platform_device *pdev)
if (suppress_preamble)
fep->phy_speed |= BIT(7);
+ /* Clear MMFR to avoid to generate MII event by writing MSCR.
+ * MII event generation condition:
+ * - writing MSCR:
+ * - mmfr[31:0]_not_zero & mscr[7:0]_is_zero &
+ * mscr_reg_data_in[7:0] != 0
+ * - writing MMFR:
+ * - mscr[7:0]_not_zero
+ */
+ writel(0, fep->hwp + FEC_MII_DATA);
+
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
/* Clear any pending transaction complete indication */