From: Cyril Chemparathy <cyril@ti.com>
To: netdev@vger.kernel.org,
davinci-linux-open-source@linux.davincidsp.com,
linux-omap@vger.kernel.org
Cc: michael.williamson@criticallink.com, caglarakyuz@gmail.com,
bparrot@ti.com, Cyril Chemparathy <cyril@ti.com>
Subject: [PATCH 7/9] net: davinci_mdio: work around emac soft-reset during i/o
Date: Mon, 13 Sep 2010 14:07:29 -0400 [thread overview]
Message-ID: <1284401251-8846-8-git-send-email-cyril@ti.com> (raw)
In-Reply-To: <1284401251-8846-1-git-send-email-cyril@ti.com>
On certain devices (e.g. da8xx), the hardware design ties emac soft-reset to
the mdio module. In these cases, when the emac device is opened, an in-flight
mdio transaction could fail by returning the controller to idle state. This
patch detects this condition and works around it by retrying the failed
transaction.
In addition, defensive timeouts have been added to prevent an indefinite
lockup in case of an unexpected hardware error.
Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Signed-off-by: Michael Williamson <michael.williamson@criticallink.com>
Signed-off-by: Caglar Akyuz <caglarakyuz@gmail.com>
---
drivers/net/davinci_mdio.c | 92 ++++++++++++++++++++++++++++++++++++-------
1 files changed, 77 insertions(+), 15 deletions(-)
diff --git a/drivers/net/davinci_mdio.c b/drivers/net/davinci_mdio.c
index f2d7639..7615040 100644
--- a/drivers/net/davinci_mdio.c
+++ b/drivers/net/davinci_mdio.c
@@ -36,6 +36,13 @@
#include <linux/io.h>
#include <linux/davinci_emac.h>
+/*
+ * This timeout definition is a worst-case ultra defensive measure against
+ * unexpected controller lock ups. Ideally, we should never ever hit this
+ * scenario in practice.
+ */
+#define MDIO_TIMEOUT 100 /* msecs */
+
#define PHY_REG_MASK 0x1f
#define PHY_ID_MASK 0x1f
@@ -150,30 +157,53 @@ static int davinci_mdio_reset(struct mii_bus *bus)
}
/* wait until hardware is ready for another user access */
-static inline u32 wait_for_user_access(struct davinci_mdio_data *data)
+static inline int wait_for_user_access(struct davinci_mdio_data *data)
{
struct davinci_mdio_regs __iomem *regs = data->regs;
+ unsigned long timeout = jiffies + msecs_to_jiffies(MDIO_TIMEOUT);
u32 reg;
- while ((reg = __raw_readl(®s->user[0].access)) & USERACCESS_GO)
- ;
-
- return reg;
+ while (time_after(timeout, jiffies)) {
+ reg = __raw_readl(®s->user[0].access);
+ if ((reg & USERACCESS_GO) == 0)
+ return 0;
+
+ reg = __raw_readl(®s->control);
+ if ((reg & CONTROL_IDLE) == 0)
+ continue;
+
+ /*
+ * An emac soft_reset may have clobbered the mdio controller's
+ * state machine. We need to reset and retry the current
+ * operation
+ */
+ dev_warn(data->dev, "resetting idled controller\n");
+ __davinci_mdio_reset(data);
+ return -EAGAIN;
+ }
+ dev_err(data->dev, "timed out waiting for user access\n");
+ return -ETIMEDOUT;
}
/* wait until hardware state machine is idle */
-static inline void wait_for_idle(struct davinci_mdio_data *data)
+static inline int wait_for_idle(struct davinci_mdio_data *data)
{
struct davinci_mdio_regs __iomem *regs = data->regs;
+ unsigned long timeout = jiffies + msecs_to_jiffies(MDIO_TIMEOUT);
- while ((__raw_readl(®s->control) & CONTROL_IDLE) == 0)
- ;
+ while (time_after(timeout, jiffies)) {
+ if (__raw_readl(®s->control) & CONTROL_IDLE)
+ return 0;
+ }
+ dev_err(data->dev, "timed out waiting for idle\n");
+ return -ETIMEDOUT;
}
static int davinci_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
{
struct davinci_mdio_data *data = bus->priv;
u32 reg;
+ int ret;
if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
return -EINVAL;
@@ -185,14 +215,32 @@ static int davinci_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
return -ENODEV;
}
- wait_for_user_access(data);
reg = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) |
(phy_id << 16));
- __raw_writel(reg, &data->regs->user[0].access);
- reg = wait_for_user_access(data);
+
+ while (1) {
+ ret = wait_for_user_access(data);
+ if (ret == -EAGAIN)
+ continue;
+ if (ret < 0)
+ break;
+
+ __raw_writel(reg, &data->regs->user[0].access);
+
+ ret = wait_for_user_access(data);
+ if (ret == -EAGAIN)
+ continue;
+ if (ret < 0)
+ break;
+
+ reg = __raw_readl(&data->regs->user[0].access);
+ ret = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -EIO;
+ break;
+ }
+
spin_unlock(&data->lock);
- return (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -EIO;
+ return ret;
}
static int davinci_mdio_write(struct mii_bus *bus, int phy_id,
@@ -200,6 +248,7 @@ static int davinci_mdio_write(struct mii_bus *bus, int phy_id,
{
struct davinci_mdio_data *data = bus->priv;
u32 reg;
+ int ret;
if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
return -EINVAL;
@@ -211,11 +260,24 @@ static int davinci_mdio_write(struct mii_bus *bus, int phy_id,
return -ENODEV;
}
- wait_for_user_access(data);
reg = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) |
(phy_id << 16) | (phy_data & USERACCESS_DATA));
- __raw_writel(reg, &data->regs->user[0].access);
- wait_for_user_access(data);
+
+ while (1) {
+ ret = wait_for_user_access(data);
+ if (ret == -EAGAIN)
+ continue;
+ if (ret < 0)
+ break;
+
+ __raw_writel(reg, &data->regs->user[0].access);
+
+ ret = wait_for_user_access(data);
+ if (ret == -EAGAIN)
+ continue;
+ break;
+ }
+
spin_unlock(&data->lock);
return 0;
--
1.7.0.4
next prev parent reply other threads:[~2010-09-13 18:07 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-09-13 18:07 [PATCH 0/9] post cpdma/mdio refactoring fixes Cyril Chemparathy
[not found] ` <1284401251-8846-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
2010-09-13 18:07 ` [PATCH 1/9] net: davinci_emac: allow forced 100/full via phy_id Cyril Chemparathy
2010-09-13 18:07 ` [PATCH 2/9] davinci: specify phy_id rather than auto-detect Cyril Chemparathy
2010-09-13 18:07 ` [PATCH 3/9] net: davinci_cpdma: requeue on early end-of-queue Cyril Chemparathy
2010-09-13 18:07 ` [PATCH 4/9] net: davinci_emac: fix rx error handling Cyril Chemparathy
2010-09-13 18:07 ` [PATCH 5/9] net: davinci_mdio: separate out controller reset Cyril Chemparathy
2010-09-13 18:07 ` [PATCH 6/9] net: davinci_mdio: use calculated bus access times Cyril Chemparathy
2010-09-13 18:07 ` Cyril Chemparathy [this message]
2010-09-13 18:07 ` [PATCH 8/9] net: davinci_cpdma: add register dump routines Cyril Chemparathy
2010-09-13 18:07 ` [PATCH 9/9] net: davinci_emac: extended register dumps on tx timeout Cyril Chemparathy
2010-09-14 18:50 ` [PATCH 0/9] post cpdma/mdio refactoring fixes Kevin Hilman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1284401251-8846-8-git-send-email-cyril@ti.com \
--to=cyril@ti.com \
--cc=bparrot@ti.com \
--cc=caglarakyuz@gmail.com \
--cc=davinci-linux-open-source@linux.davincidsp.com \
--cc=linux-omap@vger.kernel.org \
--cc=michael.williamson@criticallink.com \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).