From patchwork Tue Jan 13 16:35:28 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Thompson X-Patchwork-Id: 43066 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-we0-f198.google.com (mail-we0-f198.google.com [74.125.82.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 2AF4D20DE8 for ; Tue, 13 Jan 2015 16:36:03 +0000 (UTC) Received: by mail-we0-f198.google.com with SMTP id q59sf2276666wes.1 for ; Tue, 13 Jan 2015 08:36:02 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=/+MFZj8LlMDOxr4WPF8I1ICgcggE8l+qHHmna7Q5E+4=; b=kz5Kxyt0jTKOTutlOA055pPzCzsHeMNDjRvOKBtEJKbgmpilHd+nBGg67TTferFB7R 0vjcvbcYBZtGjSl1gGfHsojNsqouh6lhY9vP3Cy2cMxd/I40GZ2pKii4MW2VgQ5fjhVG 8S9XTkxYc0ZOvy8BL+qbNEY1bhRMMdNEIo7BzsJJy+0LxzB3AGFloG5i5QGaKXjialC6 ceJYNkI320KsnvTyWAZuPTmO8sETwG86k7//+b4KT5X3m7VTMV+ynOd+1qrfXVrOWcLf piVOlye6G9kk9xBP4meFQkJRV4q4ldDo3gG4Vv7MuaZPZV3/mEjxME/AIAr+2z4FFvHL 6z/g== X-Gm-Message-State: ALoCoQkVwcneQXp7s17vPtHhFQ5F9QDdd7ciG+RVTfjb9Ab2KPNMkVNkkcrfqxKgw/nsacwBwRgc X-Received: by 10.180.105.97 with SMTP id gl1mr2998923wib.7.1421166962483; Tue, 13 Jan 2015 08:36:02 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.42.170 with SMTP id p10ls20586lal.35.gmail; Tue, 13 Jan 2015 08:36:02 -0800 (PST) X-Received: by 10.112.13.103 with SMTP id g7mr43550756lbc.29.1421166962330; Tue, 13 Jan 2015 08:36:02 -0800 (PST) Received: from mail-la0-f54.google.com (mail-la0-f54.google.com. [209.85.215.54]) by mx.google.com with ESMTPS id ol6si24779815lbb.11.2015.01.13.08.36.02 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 13 Jan 2015 08:36:02 -0800 (PST) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.54 as permitted sender) client-ip=209.85.215.54; Received: by mail-la0-f54.google.com with SMTP id pv20so3557992lab.13 for ; Tue, 13 Jan 2015 08:36:02 -0800 (PST) X-Received: by 10.152.6.132 with SMTP id b4mr43730572laa.59.1421166962196; Tue, 13 Jan 2015 08:36:02 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.112.9.200 with SMTP id c8csp1435383lbb; Tue, 13 Jan 2015 08:36:01 -0800 (PST) X-Received: by 10.152.115.172 with SMTP id jp12mr43131607lab.33.1421166957709; Tue, 13 Jan 2015 08:35:57 -0800 (PST) Received: from mail-we0-f177.google.com (mail-we0-f177.google.com. [74.125.82.177]) by mx.google.com with ESMTPS id bc4si21223600wib.2.2015.01.13.08.35.57 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 13 Jan 2015 08:35:57 -0800 (PST) Received-SPF: pass (google.com: domain of daniel.thompson@linaro.org designates 74.125.82.177 as permitted sender) client-ip=74.125.82.177; Received: by mail-we0-f177.google.com with SMTP id q59so3942003wes.8 for ; Tue, 13 Jan 2015 08:35:57 -0800 (PST) X-Received: by 10.180.77.114 with SMTP id r18mr41475815wiw.8.1421166957289; Tue, 13 Jan 2015 08:35:57 -0800 (PST) Received: from sundance.lan (cpc4-aztw19-0-0-cust157.18-1.cable.virginm.net. [82.33.25.158]) by mx.google.com with ESMTPSA id q10sm26349181wjx.34.2015.01.13.08.35.55 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 13 Jan 2015 08:35:56 -0800 (PST) From: Daniel Thompson To: Thomas Gleixner , Jason Cooper , Russell King Cc: Daniel Thompson , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, patches@linaro.org, linaro-kernel@lists.linaro.org, John Stultz , Sumit Semwal , Dirk Behme , Daniel Drake , Dmitry Pervushin , Tim Sander , Stephen Boyd Subject: [RFC PATCH 2/5] irq: Allow interrupts to routed to NMI (or similar) Date: Tue, 13 Jan 2015 16:35:28 +0000 Message-Id: <1421166931-14134-3-git-send-email-daniel.thompson@linaro.org> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1421166931-14134-1-git-send-email-daniel.thompson@linaro.org> References: <1421166931-14134-1-git-send-email-daniel.thompson@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: daniel.thompson@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.54 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Some combinations of architectures and interrupt controllers make it possible for abitrary interrupt signals to be selectively made immune to masking by local_irq_disable(). For example, on ARM platforms, many interrupt controllers allow interrupts to be routed to FIQ rather than IRQ. These features could be exploited to implement debug and tracing features that can be implemented using NMI on x86 platforms (perf, hard lockup, kgdb). This patch assumes that the management of the NMI handler itself will be architecture specific (maybe notifier list like x86, hard coded like ARM, or something else entirely). The generic layer can still manage the irq as normal (affinity, enable/disable, free) but is not responsible for dispatching. Signed-off-by: Daniel Thompson --- include/linux/interrupt.h | 20 ++++++++++++++++++++ include/linux/irq.h | 2 ++ kernel/irq/manage.c | 29 +++++++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index d9b05b5bf8c7..b95dc28f4cc3 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -57,6 +57,9 @@ * IRQF_NO_THREAD - Interrupt cannot be threaded * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device * resume time. + * __IRQF_NMI - Route the interrupt to an NMI or some similar signal that is not + * masked by local_irq_disable(). Used internally by + * request_nmi_irq(). */ #define IRQF_DISABLED 0x00000020 #define IRQF_SHARED 0x00000080 @@ -70,6 +73,7 @@ #define IRQF_FORCE_RESUME 0x00008000 #define IRQF_NO_THREAD 0x00010000 #define IRQF_EARLY_RESUME 0x00020000 +#define __IRQF_NMI 0x00040000 #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD) @@ -139,6 +143,22 @@ extern int __must_check request_percpu_irq(unsigned int irq, irq_handler_t handler, const char *devname, void __percpu *percpu_dev_id); +static inline int __must_check request_nmi_irq(unsigned int irq, + unsigned long flags, + const char *name, void *dev_id) +{ + /* + * no_action unconditionally returns IRQ_NONE which is exactly + * what we need. The handler might be expected to be unreachable + * but some controllers may spuriously ack the NMI from the IRQ + * handling code. When this happens it occurs very rarely, thus + * by returning IRQ_NONE we can rely on the spurious interrupt + * logic to do the right thing. + */ + return request_irq(irq, no_action, flags | IRQF_NO_THREAD | __IRQF_NMI, + name, dev_id); +} + extern void free_irq(unsigned int, void *); extern void free_percpu_irq(unsigned int, void __percpu *); diff --git a/include/linux/irq.h b/include/linux/irq.h index d09ec7a1243e..695eb37f04ae 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -307,6 +307,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) * @irq_eoi: end of interrupt * @irq_set_affinity: set the CPU affinity on SMP machines * @irq_retrigger: resend an IRQ to the CPU + * @irq_set_nmi_routing:set whether interrupt can act like NMI * @irq_set_type: set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ * @irq_set_wake: enable/disable power-management wake-on of an IRQ * @irq_bus_lock: function to lock access to slow bus (i2c) chips @@ -341,6 +342,7 @@ struct irq_chip { int (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force); int (*irq_retrigger)(struct irq_data *data); + int (*irq_set_nmi_routing)(struct irq_data *data, unsigned int nmi); int (*irq_set_type)(struct irq_data *data, unsigned int flow_type); int (*irq_set_wake)(struct irq_data *data, unsigned int on); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 80692373abd6..8e669051759d 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -571,6 +571,17 @@ int can_request_irq(unsigned int irq, unsigned long irqflags) return canrequest; } +int __irq_set_nmi_routing(struct irq_desc *desc, unsigned int irq, + unsigned int nmi) +{ + struct irq_chip *chip = desc->irq_data.chip; + + if (!chip || !chip->irq_set_nmi_routing) + return -EINVAL; + + return chip->irq_set_nmi_routing(&desc->irq_data, nmi); +} + int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, unsigned long flags) { @@ -1058,11 +1069,12 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) * the same type (level, edge, polarity). So both flag * fields must have IRQF_SHARED set and the bits which * set the trigger type must match. Also all must - * agree on ONESHOT. + * agree on ONESHOT and NMI */ if (!((old->flags & new->flags) & IRQF_SHARED) || ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK) || - ((old->flags ^ new->flags) & IRQF_ONESHOT)) + ((old->flags ^ new->flags) & IRQF_ONESHOT) || + ((old->flags ^ new->flags) & __IRQF_NMI)) goto mismatch; /* All handlers must agree on per-cpuness */ @@ -1153,6 +1165,19 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) init_waitqueue_head(&desc->wait_for_threads); + if (new->flags & __IRQF_NMI) { + ret = __irq_set_nmi_routing(desc, irq, true); + if (ret != 1) + goto out_mask; + } else { + ret = __irq_set_nmi_routing(desc, irq, false); + if (ret == 1) { + pr_err("Failed to disable NMI routing for irq %d\n", + irq); + goto out_mask; + } + } + /* Setup the type (level, edge polarity) if configured: */ if (new->flags & IRQF_TRIGGER_MASK) { ret = __irq_set_trigger(desc, irq,