From patchwork Wed Apr 24 18:48:25 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sebastian Andrzej Siewior X-Patchwork-Id: 239290 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 581862C0100 for ; Thu, 25 Apr 2013 04:48:42 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757387Ab3DXSsk (ORCPT ); Wed, 24 Apr 2013 14:48:40 -0400 Received: from www.linutronix.de ([62.245.132.108]:41177 "EHLO Galois.linutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757332Ab3DXSsh (ORCPT ); Wed, 24 Apr 2013 14:48:37 -0400 Received: from localhost ([127.0.0.1] helo=localhost.localdomain) by Galois.linutronix.de with esmtp (Exim 4.72) (envelope-from ) id 1UV4k8-0004G4-QW; Wed, 24 Apr 2013 20:48:37 +0200 From: Sebastian Andrzej Siewior To: Mugunthan V N Cc: tglx@linutronix.de, netdev@vger.kernel.org, "David S. Miller" , Sebastian Andrzej Siewior Subject: [PATCH 4/4] net/cpsw: fix irq_disable() with threaded interrupts Date: Wed, 24 Apr 2013 20:48:25 +0200 Message-Id: <1366829305-9752-5-git-send-email-bigeasy@linutronix.de> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1366829305-9752-1-git-send-email-bigeasy@linutronix.de> References: <1366829305-9752-1-git-send-email-bigeasy@linutronix.de> X-Linutronix-Spam-Score: -1.0 X-Linutronix-Spam-Level: - X-Linutronix-Spam-Status: No , -1.0 points, 5.0 required, ALL_TRUSTED=-1, SHORTCIRCUIT=-0.0001 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org During high throughput it is likely that we receive both: an RX and TX interrupt. The normal behaviour is that once we enter the ISR the interrupts are disabled in the IRQ chip and so the ISR is invoked only once and the interrupt line is disabled once. It will be re-enabled after napi completes. With threaded interrupts on the other hand the interrupt the interrupt is disabled immediately and the ISR is marked for "later". By having TX and RX interrupt marked pending we invoke them both and disable the interrupt line twice. The napi callback is still executed once and so after it completes we remain with interrupts disabled. The initial patch simply removed the cpsw_{enable|disable}_irq() calls and it worked well on my AM335X ES1.0 (beagle bone). On ES2.0 (beagle bone black) it caused an never ending interrupt (even after the mask via cpsw_intr_disable()) according to Mugunthan V N. Since I don't have the ES2.0 and no idea what is going on this patch tracks the state of the irq_disable() call and execute it only when not yet done. The book keeping is done on the first struct since with dual_emac we can have two of those and only one interrupt line. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Mugunthan V N --- drivers/net/ethernet/ti/cpsw.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 8b643d9..2633be6 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -348,6 +348,7 @@ struct cpsw_priv { /* snapshot of IRQ numbers */ u32 irqs_table[4]; u32 num_irqs; + bool irq_enabled; struct cpts *cpts; u32 emac_port; }; @@ -515,7 +516,10 @@ static irqreturn_t cpsw_interrupt(int irq, void *dev_id) return IRQ_NONE; cpsw_intr_disable(priv); - cpsw_disable_irq(priv); + if (priv->irq_enabled == true) { + cpsw_disable_irq(priv); + priv->irq_enabled = false; + } if (netif_running(priv->ndev)) { napi_schedule(&priv->napi); @@ -544,10 +548,16 @@ static int cpsw_poll(struct napi_struct *napi, int budget) num_rx = cpdma_chan_process(priv->rxch, budget); if (num_rx < budget) { + struct cpsw_priv *prim_cpsw; + napi_complete(napi); cpsw_intr_enable(priv); cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); - cpsw_enable_irq(priv); + prim_cpsw = cpsw_get_slave_priv(priv, 0); + if (prim_cpsw->irq_enabled == false) { + cpsw_enable_irq(priv); + prim_cpsw->irq_enabled = true; + } } if (num_rx || num_tx) @@ -886,6 +896,7 @@ static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv) static int cpsw_ndo_open(struct net_device *ndev) { struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_priv *prim_cpsw; int i, ret; u32 reg; @@ -953,6 +964,14 @@ static int cpsw_ndo_open(struct net_device *ndev) cpsw_set_coalesce(ndev, &coal); } + prim_cpsw = cpsw_get_slave_priv(priv, 0); + if (prim_cpsw->irq_enabled == false) { + if ((priv == prim_cpsw) || !netif_running(prim_cpsw->ndev)) { + prim_cpsw->irq_enabled = true; + cpsw_enable_irq(prim_cpsw); + } + } + cpdma_ctlr_start(priv->dma); cpsw_intr_enable(priv); napi_enable(&priv->napi); @@ -1856,7 +1875,7 @@ static int cpsw_probe(struct platform_device *pdev) } k++; } - + priv->irq_enabled = true; ndev->features |= NETIF_F_HW_VLAN_FILTER; ndev->netdev_ops = &cpsw_netdev_ops;