From patchwork Mon Jul 7 23:22:44 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russell King X-Patchwork-Id: 4498511 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id E34AD9F26C for ; Mon, 7 Jul 2014 23:25:18 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id F2BC12034F for ; Mon, 7 Jul 2014 23:25:17 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2A84F20328 for ; Mon, 7 Jul 2014 23:25:17 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1X4IFZ-0002C5-Gh; Mon, 07 Jul 2014 23:23:09 +0000 Received: from pandora.arm.linux.org.uk ([2001:4d48:ad52:3201:214:fdff:fe10:1be6]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1X4IFS-000236-Ux for linux-arm-kernel@lists.infradead.org; Mon, 07 Jul 2014 23:23:03 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=arm.linux.org.uk; s=pandora-2014; h=Date:Sender:Message-Id:Subject:Cc:To:From:References:In-Reply-To; bh=lt7f9Xz7bxRIKEfM8YivTCKSFDZvJ7uZhNgnOY7clk0=; b=B3580+Si59Ab4hPlTsnocmNzNTqCG0W4kDTCFXCXnz2SKKldQGmDaHzTW7zcQaJ7g/pCDQCL85UnsDpKRj/uCN1Rqvqvp7jZOve2Yh/Hfini764BtJFVeoMxbgoR9xEZrtTj+83JVUCIurk+6MJ5uPCtN+8lpVp1lsfxgVu/s0Q=; Received: from e0022681537dd.dyn.arm.linux.org.uk ([2002:4e20:1eda:1:222:68ff:fe15:37dd]:48933 helo=rmk-PC.arm.linux.org.uk) by pandora.arm.linux.org.uk with esmtpsa (TLSv1:AES256-SHA:256) (Exim 4.76) (envelope-from ) id 1X4IFA-0005B4-Hi; Tue, 08 Jul 2014 00:22:44 +0100 Received: from rmk by rmk-PC.arm.linux.org.uk with local (Exim 4.76) (envelope-from ) id 1X4IFA-0004wp-6x; Tue, 08 Jul 2014 00:22:44 +0100 In-Reply-To: <20140707232148.GG21766@n2100.arm.linux.org.uk> References: <20140707232148.GG21766@n2100.arm.linux.org.uk> From: Russell King To: "David S. Miller" Subject: [PATCH A 03/12] net: fec: fix interrupt handling races Message-Id: Date: Tue, 08 Jul 2014 00:22:44 +0100 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140707_162303_403644_D9A74B8D X-CRM114-Status: GOOD ( 17.86 ) X-Spam-Score: -0.8 (/) Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.4 required=5.0 tests=BAYES_00,DKIM_SIGNED, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP While running: while :; do iperf -c -P 4; done, transmit timeouts are regularly reported. With the tx ring dumping in place, we can see that all entries are in use, and the hardware has finished transmitting these packets. However, the driver has not reclaimed these ring entries. This can occur if the interrupt handler is invoked at the wrong moment - eg: CPU0 CPU1 fec_enet_tx() interrupt, IEVENT = FEC_ENET_TXF FEC_ENET_TXF cleared napi_schedule_prep() napi_complete() The result is that we clear the transmit interrupt, but we don't trigger any cleaning of the transmit ring. Instead, use a different strategy: - When receiving a transmit or receive interrupt, disable both tx and rx interrupts, but do not acknowledge them. Schedule a napi poll. Don't loop. - When we are polled, read IEVENT, acknowledging the pending transmit and receive interrupts, before then going on to process the appropriate rings. This allows us to avoid the race, and has a number of other advantages: - we cut down on the number of transmit interrupts we have to process. - we only look at the rings which have pending events. - we gain additional throughput: the iperf total bandwidth increases from about 180Mbps to 240Mbps: [ 3] 0.0-10.0 sec 68.1 MBytes 57.0 Mbits/sec [ 5] 0.0-10.0 sec 72.4 MBytes 60.5 Mbits/sec [ 4] 0.0-10.1 sec 76.1 MBytes 63.5 Mbits/sec [ 6] 0.0-10.1 sec 71.9 MBytes 59.9 Mbits/sec [SUM] 0.0-10.1 sec 288 MBytes 241 Mbits/sec Acked-by: Fugang Duan Signed-off-by: Russell King --- drivers/net/ethernet/freescale/fec_main.c | 40 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 045ea71f2b59..4e695b742030 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1369,29 +1369,25 @@ fec_enet_interrupt(int irq, void *dev_id) { struct net_device *ndev = dev_id; struct fec_enet_private *fep = netdev_priv(ndev); + const unsigned napi_mask = FEC_ENET_RXF | FEC_ENET_TXF; uint int_events; irqreturn_t ret = IRQ_NONE; - do { - int_events = readl(fep->hwp + FEC_IEVENT); - writel(int_events, fep->hwp + FEC_IEVENT); + int_events = readl(fep->hwp + FEC_IEVENT); + writel(int_events & ~napi_mask, fep->hwp + FEC_IEVENT); - if (int_events & (FEC_ENET_RXF | FEC_ENET_TXF)) { - ret = IRQ_HANDLED; + if (int_events & napi_mask) { + ret = IRQ_HANDLED; - /* Disable the RX interrupt */ - if (napi_schedule_prep(&fep->napi)) { - writel(FEC_RX_DISABLED_IMASK, - fep->hwp + FEC_IMASK); - __napi_schedule(&fep->napi); - } - } + /* Disable the NAPI interrupts */ + writel(FEC_ENET_MII, fep->hwp + FEC_IMASK); + napi_schedule(&fep->napi); + } - if (int_events & FEC_ENET_MII) { - ret = IRQ_HANDLED; - complete(&fep->mdio_done); - } - } while (int_events); + if (int_events & FEC_ENET_MII) { + ret = IRQ_HANDLED; + complete(&fep->mdio_done); + } return ret; } @@ -1399,8 +1395,16 @@ fec_enet_interrupt(int irq, void *dev_id) static int fec_enet_rx_napi(struct napi_struct *napi, int budget) { struct net_device *ndev = napi->dev; - int pkts = fec_enet_rx(ndev, budget); struct fec_enet_private *fep = netdev_priv(ndev); + int pkts; + + /* + * Clear any pending transmit or receive interrupts before + * processing the rings to avoid racing with the hardware. + */ + writel(FEC_ENET_RXF | FEC_ENET_TXF, fep->hwp + FEC_IEVENT); + + pkts = fec_enet_rx(ndev, budget); fec_enet_tx(ndev);