From patchwork Tue Jan 29 15:24:06 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Fainelli X-Patchwork-Id: 2062481 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id E67763FCD5 for ; Tue, 29 Jan 2013 15:31:04 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1U0D6p-0000dh-UM; Tue, 29 Jan 2013 15:28:27 +0000 Received: from zmc.proxad.net ([212.27.53.206]) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1U0D5Z-00007J-Hb for linux-arm-kernel@lists.infradead.org; Tue, 29 Jan 2013 15:27:14 +0000 Received: from localhost (localhost [127.0.0.1]) by zmc.proxad.net (Postfix) with ESMTP id 10622BF7C12; Tue, 29 Jan 2013 16:27:08 +0100 (CET) X-Virus-Scanned: amavisd-new at localhost Received: from zmc.proxad.net ([127.0.0.1]) by localhost (zmc.proxad.net [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id IO1NBOf-owUw; Tue, 29 Jan 2013 16:27:06 +0100 (CET) Received: from flexo.localdomain (freebox.vlq16.iliad.fr [213.36.7.13]) by zmc.proxad.net (Postfix) with ESMTPSA id 7AF4CBF6ED1; Tue, 29 Jan 2013 16:27:06 +0100 (CET) From: Florian Fainelli To: davem@davemloft.net Subject: [PATCH 3/5] net: mvmdio: enhance driver to support SMI error/done interrupts Date: Tue, 29 Jan 2013 16:24:06 +0100 Message-Id: <1359473048-26551-4-git-send-email-florian@openwrt.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1359473048-26551-1-git-send-email-florian@openwrt.org> References: <1359473048-26551-1-git-send-email-florian@openwrt.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130129_102709_867188_44A66078 X-CRM114-Status: GOOD ( 20.20 ) X-Spam-Score: 1.1 (+) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (1.1 points) pts rule name description ---- ---------------------- -------------------------------------------------- 3.0 KHOP_BIG_TO_CC Sent to 10+ recipients instaed of Bcc or a list -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Thomas Petazzoni , Andrew Lunn , Russell King , Jason Cooper , linux-doc@vger.kernel.org, Benjamin Herrenschmidt , devicetree-discuss@lists.ozlabs.org, linux-kernel@vger.kernel.org, Rob Herring , Grant Likely , netdev@vger.kernel.org, Paul Mackerras , linux-arm-kernel@lists.infradead.org, Rob Landley , Greg Kroah-Hartman , linuxppc-dev@lists.ozlabs.org, Florian Fainelli , Lennert Buytenhek X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org This patch enhances the "mvmdio" to support a SMI error/done interrupt line which can be used along with a wait queue instead of doing busy-waiting on the registers. This is a feature which is available in the mv643xx_eth SMI code and thus reduces again the gap between the two. Signed-off-by: Florian Fainelli --- .../devicetree/bindings/net/marvell-orion-mdio.txt | 3 + drivers/net/ethernet/marvell/mvmdio.c | 83 +++++++++++++++++--- 2 files changed, 75 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt b/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt index 34e7aaf..052b5f2 100644 --- a/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt +++ b/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt @@ -9,6 +9,9 @@ Required properties: - compatible: "marvell,orion-mdio" - reg: address and length of the SMI register +Optional properties: +- interrupts: interrupt line number for the SMI error/done interrupt + The child nodes of the MDIO driver are the individual PHY devices connected to this MDIO bus. They must have a "reg" property given the PHY address on the MDIO bus. diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 5ecda58..cada794 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -24,10 +24,14 @@ #include #include #include +#include #include #include +#include #include #include +#include +#include #define MVMDIO_SMI_DATA_SHIFT 0 #define MVMDIO_SMI_PHY_ADDR_SHIFT 16 @@ -36,12 +40,28 @@ #define MVMDIO_SMI_WRITE_OPERATION 0 #define MVMDIO_SMI_READ_VALID BIT(27) #define MVMDIO_SMI_BUSY BIT(28) +#define MVMDIO_ERR_INT_CAUSE 0x007C +#define MVMDIO_ERR_INT_SMI_DONE 0x00000010 +#define MVMDIO_ERR_INT_MASK 0x0080 struct orion_mdio_dev { struct mutex lock; void __iomem *regs; + /* + * If we have access to the error interrupt pin (which is + * somewhat misnamed as it not only reflects internal errors + * but also reflects SMI completion), use that to wait for + * SMI access completion instead of polling the SMI busy bit. + */ + int err_interrupt; + wait_queue_head_t smi_busy_wait; }; +static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev) +{ + return !(readl(dev->regs) & MVMDIO_SMI_BUSY); +} + /* Wait for the SMI unit to be ready for another operation */ static int orion_mdio_wait_ready(struct mii_bus *bus) @@ -50,19 +70,30 @@ static int orion_mdio_wait_ready(struct mii_bus *bus) int count; u32 val; - count = 0; - while (1) { - val = readl(dev->regs); - if (!(val & MVMDIO_SMI_BUSY)) - break; - - if (count > 100) { - dev_err(bus->parent, "Timeout: SMI busy for too long\n"); - return -ETIMEDOUT; + if (dev->err_interrupt == NO_IRQ) { + count = 0; + while (1) { + val = readl(dev->regs); + if (!(val & MVMDIO_SMI_BUSY)) + break; + + if (count > 100) { + dev_err(bus->parent, + "Timeout: SMI busy for too long\n"); + return -ETIMEDOUT; + } + + udelay(10); + count++; } + } - udelay(10); - count++; + if (!orion_mdio_smi_is_done(dev)) { + wait_event_timeout(dev->smi_busy_wait, + orion_mdio_smi_is_done(dev), + msecs_to_jiffies(100)); + if (!orion_mdio_smi_is_done(dev)) + return -ETIMEDOUT; } return 0; @@ -141,6 +172,21 @@ static int orion_mdio_reset(struct mii_bus *bus) return 0; } +static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id) +{ + struct orion_mdio_dev *dev = dev_id; + + if (readl(dev->regs + MVMDIO_ERR_INT_CAUSE) & + MVMDIO_ERR_INT_SMI_DONE) { + writel(~MVMDIO_ERR_INT_SMI_DONE, + dev->regs + MVMDIO_ERR_INT_CAUSE); + wake_up(&dev->smi_busy_wait); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + static int orion_mdio_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -181,6 +227,19 @@ static int orion_mdio_probe(struct platform_device *pdev) return -ENODEV; } + dev->err_interrupt = NO_IRQ; + init_waitqueue_head(&dev->smi_busy_wait); + + dev->err_interrupt = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (dev->err_interrupt != NO_IRQ) { + ret = devm_request_irq(&pdev->dev, dev->err_interrupt, + orion_mdio_err_irq, + IRQF_SHARED, pdev->name, dev); + if (!ret) + writel(MVMDIO_ERR_INT_SMI_DONE, + dev->regs + MVMDIO_ERR_INT_MASK); + } + mutex_init(&dev->lock); ret = of_mdiobus_register(bus, np); @@ -202,6 +261,8 @@ static int orion_mdio_remove(struct platform_device *pdev) struct mii_bus *bus = platform_get_drvdata(pdev); struct orion_mdio_dev *dev = bus->priv; + writel(0, dev->regs + MVMDIO_ERR_INT_MASK); + free_irq(dev->err_interrupt, dev); mdiobus_unregister(bus); kfree(bus->irq); mdiobus_free(bus);