summaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2018-12-11 15:46:50 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2018-12-14 11:24:25 +0100
commitf21120883135e1bd2f5e9441f5265857196a81ff (patch)
tree1492661236ff1c0b3837b07bb02d6456a811f77d /drivers/net
parent244f7dc385271c3fad5f3b842416985540b3664f (diff)
downloadbarebox-f21120883135e1bd2f5e9441f5265857196a81ff.tar.gz
barebox-f21120883135e1bd2f5e9441f5265857196a81ff.tar.xz
net: davinci-emac: Add timeout to polling loop
Do not poll forever when the hardware does not behave like we want to. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/davinci_emac.c47
1 files changed, 38 insertions, 9 deletions
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index 2f6091d155..bda62214ef 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -105,13 +105,40 @@ static void davinci_eth_mdio_enable(struct davinci_emac_priv *priv)
while (readl(priv->adap_mdio + EMAC_MDIO_CONTROL) & MDIO_CONTROL_IDLE);
}
+/* wait until hardware is ready for another user access */
+static int wait_for_user_access(struct davinci_emac_priv *priv, uint32_t *val)
+{
+ u32 tmp;
+ uint64_t start = get_time_ns();
+
+ do {
+ tmp = readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0);
+
+ if (!(tmp & MDIO_USERACCESS0_GO))
+ break;
+
+ if (is_timeout(start, 100 * MSECOND)) {
+ dev_err(priv->dev, "timeout waiting for user access\n");
+ return -ETIMEDOUT;
+ }
+ } while (1);
+
+ if (val)
+ *val = tmp;
+
+ return 0;
+}
+
+
static int davinci_miibus_read(struct mii_bus *bus, int addr, int reg)
{
struct davinci_emac_priv *priv = bus->priv;
uint16_t value;
- int tmp;
+ int tmp, ret;
- while (readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+ ret = wait_for_user_access(priv, NULL);
+ if (ret)
+ return ret;
writel(MDIO_USERACCESS0_GO |
MDIO_USERACCESS0_WRITE_READ |
@@ -119,8 +146,9 @@ static int davinci_miibus_read(struct mii_bus *bus, int addr, int reg)
((addr & 0x1f) << 16),
priv->adap_mdio + EMAC_MDIO_USERACCESS0);
- /* Wait for command to complete */
- while ((tmp = readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0)) & MDIO_USERACCESS0_GO);
+ ret = wait_for_user_access(priv, &tmp);
+ if (ret)
+ return ret;
if (tmp & MDIO_USERACCESS0_ACK) {
value = tmp & 0xffff;
@@ -135,7 +163,11 @@ static int davinci_miibus_read(struct mii_bus *bus, int addr, int reg)
static int davinci_miibus_write(struct mii_bus *bus, int addr, int reg, u16 value)
{
struct davinci_emac_priv *priv = bus->priv;
- while (readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+ int ret;
+
+ ret = wait_for_user_access(priv, NULL);
+ if (ret)
+ return ret;
dev_dbg(priv->dev, "davinci_miibus_write: addr=0x%02x reg=0x%02x value=0x%04x\n",
addr, reg, value);
@@ -146,10 +178,7 @@ static int davinci_miibus_write(struct mii_bus *bus, int addr, int reg, u16 valu
(value & 0xffff),
priv->adap_mdio + EMAC_MDIO_USERACCESS0);
- /* Wait for command to complete */
- while (readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
-
- return 0;
+ return wait_for_user_access(priv, NULL);
}
static int davinci_emac_get_ethaddr(struct eth_device *edev, unsigned char *adr)