Skip to content

Commit 6198c72

Browse files
wkzkuba-moo
authored andcommitted
net/fsl: xgmac_mdio: Add workaround for erratum A-009885
Once an MDIO read transaction is initiated, we must read back the data register within 16 MDC cycles after the transaction completes. Outside of this window, reads may return corrupt data. Therefore, disable local interrupts in the critical section, to maximize the probability that we can satisfy this requirement. Fixes: d55ad29 ("powerpc/mpc85xx: Create dts components for the FSL QorIQ DPAA FMan") Signed-off-by: Tobias Waldekranz <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent baa5950 commit 6198c72

File tree

1 file changed

+19
-6
lines changed

1 file changed

+19
-6
lines changed

drivers/net/ethernet/freescale/xgmac_mdio.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ struct tgec_mdio_controller {
5151
struct mdio_fsl_priv {
5252
struct tgec_mdio_controller __iomem *mdio_base;
5353
bool is_little_endian;
54+
bool has_a009885;
5455
bool has_a011043;
5556
};
5657

@@ -186,10 +187,10 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
186187
{
187188
struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;
188189
struct tgec_mdio_controller __iomem *regs = priv->mdio_base;
190+
unsigned long flags;
189191
uint16_t dev_addr;
190192
uint32_t mdio_stat;
191193
uint32_t mdio_ctl;
192-
uint16_t value;
193194
int ret;
194195
bool endian = priv->is_little_endian;
195196

@@ -221,26 +222,36 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
221222
return ret;
222223
}
223224

225+
if (priv->has_a009885)
226+
/* Once the operation completes, i.e. MDIO_STAT_BSY clears, we
227+
* must read back the data register within 16 MDC cycles.
228+
*/
229+
local_irq_save(flags);
230+
224231
/* Initiate the read */
225232
xgmac_write32(mdio_ctl | MDIO_CTL_READ, &regs->mdio_ctl, endian);
226233

227234
ret = xgmac_wait_until_done(&bus->dev, regs, endian);
228235
if (ret)
229-
return ret;
236+
goto irq_restore;
230237

231238
/* Return all Fs if nothing was there */
232239
if ((xgmac_read32(&regs->mdio_stat, endian) & MDIO_STAT_RD_ER) &&
233240
!priv->has_a011043) {
234241
dev_dbg(&bus->dev,
235242
"Error while reading PHY%d reg at %d.%hhu\n",
236243
phy_id, dev_addr, regnum);
237-
return 0xffff;
244+
ret = 0xffff;
245+
} else {
246+
ret = xgmac_read32(&regs->mdio_data, endian) & 0xffff;
247+
dev_dbg(&bus->dev, "read %04x\n", ret);
238248
}
239249

240-
value = xgmac_read32(&regs->mdio_data, endian) & 0xffff;
241-
dev_dbg(&bus->dev, "read %04x\n", value);
250+
irq_restore:
251+
if (priv->has_a009885)
252+
local_irq_restore(flags);
242253

243-
return value;
254+
return ret;
244255
}
245256

246257
static int xgmac_mdio_probe(struct platform_device *pdev)
@@ -287,6 +298,8 @@ static int xgmac_mdio_probe(struct platform_device *pdev)
287298
priv->is_little_endian = device_property_read_bool(&pdev->dev,
288299
"little-endian");
289300

301+
priv->has_a009885 = device_property_read_bool(&pdev->dev,
302+
"fsl,erratum-a009885");
290303
priv->has_a011043 = device_property_read_bool(&pdev->dev,
291304
"fsl,erratum-a011043");
292305

0 commit comments

Comments
 (0)