From patchwork Thu Oct 13 20:35:30 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "dalias@libc.org" X-Patchwork-Id: 9375733 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 781A860865 for ; Thu, 13 Oct 2016 20:37:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 691AC2A101 for ; Thu, 13 Oct 2016 20:37:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5D5842A105; Thu, 13 Oct 2016 20:37:08 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CADF92A103 for ; Thu, 13 Oct 2016 20:37:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755317AbcJMUhD (ORCPT ); Thu, 13 Oct 2016 16:37:03 -0400 Received: from 216-12-86-13.cv.mvl.ntelos.net ([216.12.86.13]:55996 "EHLO brightrain.aerifal.cx" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753613AbcJMUgg (ORCPT ); Thu, 13 Oct 2016 16:36:36 -0400 Received: from dalias by brightrain.aerifal.cx with local (Exim 3.15 #2) id 1bumiw-0001Mr-00; Thu, 13 Oct 2016 20:35:30 +0000 Message-Id: From: Rich Felker Subject: [PATCH v3] irqchip/jcore: fix lost per-cpu interrupts To: linux-kernel@vger.kernel.org, linux-sh@vger.kernel.org Cc: Thomas Gleixner , Jason Cooper , Marc Zyngier Date: Thu, 13 Oct 2016 20:35:30 +0000 Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The J-Core AIC does not have separate interrupt numbers reserved for cpu-local vs global interrupts. Instead, the driver requesting the irq is expected to know whether its device uses per-cpu interrupts or not. Previously it was assumed that handle_simple_irq could work for both cases, but it intentionally drops interrupts for an irq number that already has a handler running. This resulted in the timer interrupt for one cpu being lost when multiple cpus' timers were set for approximately the same expiration time, leading to stalls. In theory the same could also happen with IPIs. To solve the problem, instead of registering handle_simple_irq as the handler, register a wrapper function which checks whether the irq to be handled was requested as per-cpu or not, and passes it to handle_simple_irq or handle_percpu_irq accordingly. Signed-off-by: Rich Felker --- I've reverted to conditionally using handle_percpu_irq or handle_simple_irq, like the v1 patch, but with Thomas Gleixner's suggestion to make the check less costly. No failures were observed with the v2 patch but I'd rather have the fix be safe/future-proof than save a few cycles. --- drivers/irqchip/irq-jcore-aic.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-jcore-aic.c b/drivers/irqchip/irq-jcore-aic.c index 5e5e3bb..ed4d233 100644 --- a/drivers/irqchip/irq-jcore-aic.c +++ b/drivers/irqchip/irq-jcore-aic.c @@ -25,12 +25,30 @@ static struct irq_chip jcore_aic; +/* + * The J-Core AIC1 and AIC2 are cpu-local interrupt controllers and do + * not distinguish or use distinct irq number ranges for per-cpu event + * interrupts (timer, IPI). Since information to determine whether a + * particular irq number should be treated as per-cpu is not available + * at mapping time, we use a wrapper handler function which chooses + * the right handler at runtime based on whether IRQF_PERCPU was used + * when requesting the irq. + */ + +static void handle_jcore_irq(struct irq_desc *desc) +{ + if (irqd_is_per_cpu(irq_desc_get_irq_data(desc))) + handle_percpu_irq(desc); + else + handle_simple_irq(desc); +} + static int jcore_aic_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { struct irq_chip *aic = d->host_data; - irq_set_chip_and_handler(irq, aic, handle_simple_irq); + irq_set_chip_and_handler(irq, aic, handle_jcore_irq); return 0; }