From patchwork Tue Sep 2 13:00:40 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Thompson X-Patchwork-Id: 36472 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qc0-f198.google.com (mail-qc0-f198.google.com [209.85.216.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 5494E203BE for ; Tue, 2 Sep 2014 13:03:27 +0000 (UTC) Received: by mail-qc0-f198.google.com with SMTP id r5sf22234936qcx.5 for ; Tue, 02 Sep 2014 06:03:27 -0700 (PDT) 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=KHwUZqXCggmg6InxKDyZXGQdEb0a6jwKgUU+J7920BA=; b=X8Y+jOVI3bD/w371BaN1p7zKmnpNNvhI9uMU1M7/o75MWkzWMWBIz6jXu5S70SV+P5 BD7wEFptnAkeewyNrAmxVb0VrMSBQTDZPtbbcmeT0Qx2UJyVW1ShaKoGS9VX2+xbfZKe v48EPG13VwUMLJft6eNWYHjbWtN2bAwk0/JVzkk0/Um90a+5tQtPqZchC8pbmed5AuDp Oz7jQBPSXq7wo5vo4yjhjLFH+IIkI1+8NH6QbiUsKxlmVX0tFMQ1ve57WrKK7+IHKkNk /cDgtRPYBRHFshvNDnbO/2RxeBCBqPcY/gA0KNZp2CIQEAdc2zIK/78OtgES/eLADzTa dfMg== X-Gm-Message-State: ALoCoQnRNvtiDty9+00b2jdtkDfn7Q0TBksx1+uLgvEAN1jaQo7ZBdNeW1DCwlXDdOCWcuaaTJVv X-Received: by 10.236.100.134 with SMTP id z6mr18761695yhf.8.1409663007161; Tue, 02 Sep 2014 06:03:27 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.22.17 with SMTP id 17ls2361128qgm.63.gmail; Tue, 02 Sep 2014 06:03:27 -0700 (PDT) X-Received: by 10.221.6.201 with SMTP id ol9mr29974591vcb.2.1409663007045; Tue, 02 Sep 2014 06:03:27 -0700 (PDT) Received: from mail-vc0-f173.google.com (mail-vc0-f173.google.com [209.85.220.173]) by mx.google.com with ESMTPS id qn4si2216417vdb.45.2014.09.02.06.03.27 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 02 Sep 2014 06:03:27 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.173 as permitted sender) client-ip=209.85.220.173; Received: by mail-vc0-f173.google.com with SMTP id im17so6918205vcb.32 for ; Tue, 02 Sep 2014 06:03:27 -0700 (PDT) X-Received: by 10.220.163.69 with SMTP id z5mr30010282vcx.10.1409663006948; Tue, 02 Sep 2014 06:03:26 -0700 (PDT) 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.221.45.67 with SMTP id uj3csp524081vcb; Tue, 2 Sep 2014 06:03:26 -0700 (PDT) X-Received: by 10.194.237.194 with SMTP id ve2mr10414670wjc.89.1409663005543; Tue, 02 Sep 2014 06:03:25 -0700 (PDT) Received: from mail-wg0-f41.google.com (mail-wg0-f41.google.com [74.125.82.41]) by mx.google.com with ESMTPS id md6si5871315wjb.111.2014.09.02.06.03.25 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 02 Sep 2014 06:03:25 -0700 (PDT) Received-SPF: pass (google.com: domain of daniel.thompson@linaro.org designates 74.125.82.41 as permitted sender) client-ip=74.125.82.41; Received: by mail-wg0-f41.google.com with SMTP id l18so6846547wgh.12 for ; Tue, 02 Sep 2014 06:03:25 -0700 (PDT) X-Received: by 10.194.5.162 with SMTP id t2mr2954865wjt.97.1409663004830; Tue, 02 Sep 2014 06:03:24 -0700 (PDT) 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 ec2sm34928892wib.19.2014.09.02.06.03.22 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 02 Sep 2014 06:03:23 -0700 (PDT) From: Daniel Thompson To: Russell King Cc: Daniel Thompson , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, kgdb-bugreport@lists.sourceforge.net, patches@linaro.org, linaro-kernel@lists.linaro.org, John Stultz , Anton Vorontsov , Colin Cross , kernel-team@android.com, Rob Herring , Linus Walleij , Ben Dooks , Catalin Marinas , Dave Martin , Fabio Estevam , Frederic Weisbecker , Nicolas Pitre , Thomas Gleixner , Jason Cooper , Nicolas Pitre , Christoffer Dall , Sricharan R , Marc Zyngier Subject: [PATCH v11 06/19] irqchip: gic: Provide support for interrupt grouping Date: Tue, 2 Sep 2014 14:00:40 +0100 Message-Id: <1409662853-29313-7-git-send-email-daniel.thompson@linaro.org> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1409662853-29313-1-git-send-email-daniel.thompson@linaro.org> References: <1408466769-20004-1-git-send-email-daniel.thompson@linaro.org> <1409662853-29313-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.220.173 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: , All GIC hardware except GICv1-without-TrustZone support provides a means to group exceptions into group 0 (which can optionally be signally using use FIQ) and group 1. The kernel currently provides no means to exploit this. This patch alters the initialization of the GIC to place all interrupts into group 1 which is the foundational requirement to meaningfully use FIQ. Note that the hardware functionality is unavailable to the kernel when a secure monitor is present because access to the grouping registers are prohibited outside "secure world" (this feature allows grouping to be used to allow hardware peripherals to send interrupts into the secure world). The GIC driver will automatically detect this and disable its attempts to group interrupts. On systems without TrustZone support the kernel has the power to route interrupt sources to FIQ, potentially allowing a driver to exploit the NMI-like properties of FIQ. Tested on Freescale i.MX6 (quad A9), STiH416 (dual A9) and a self-written qemu GICv2 model. Signed-off-by: Daniel Thompson Cc: Thomas Gleixner Cc: Jason Cooper Cc: Nicolas Pitre Cc: Christoffer Dall Cc: Sricharan R Cc: Marc Zyngier Acked-by: Dirk Behme --- drivers/irqchip/irq-gic.c | 99 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4b959e6..423707c 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -41,6 +41,9 @@ #include #include +#ifdef CONFIG_FIQ +#include +#endif #include #include #include @@ -68,6 +71,9 @@ struct gic_chip_data { #ifdef CONFIG_GIC_NON_BANKED void __iomem *(*get_base)(union gic_base *); #endif +#ifdef CONFIG_FIQ + bool fiq_enable; +#endif }; static DEFINE_RAW_SPINLOCK(irq_controller_lock); @@ -131,6 +137,16 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data, #define gic_set_base_accessor(d, f) #endif +#ifdef CONFIG_FIQ +static inline bool gic_data_fiq_enable(struct gic_chip_data *data) +{ + return data->fiq_enable; +} +#else +static inline bool gic_data_fiq_enable( + struct gic_chip_data *data) { return false; } +#endif + static inline void __iomem *gic_dist_base(struct irq_data *d) { struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); @@ -325,6 +341,42 @@ static struct irq_chip gic_chip = { .irq_set_wake = gic_set_wake, }; +#ifdef CONFIG_FIQ +static void __init gic_init_fiq(struct gic_chip_data *gic, + irq_hw_number_t first_irq, + unsigned int num_irqs) +{ + void __iomem *dist_base = gic_data_dist_base(gic_data); + unsigned int i; + + /* + * FIQ can only be supported on platforms without an extended irq_eoi + * method (otherwise we take a lock during eoi handling). + */ + if (gic_arch_extn.irq_eoi) + return; + + /* + * If grouping is not available (not implemented or prohibited by + * security mode) these registers a read-as-zero/write-ignored. + * However as a precaution we restore the reset default regardless of + * the result of the test. + */ + writel_relaxed(1, dist_base + GIC_DIST_IGROUP + 0); + gic->fiq_enable = readl_relaxed(dist_base + GIC_DIST_IGROUP + 0); + writel_relaxed(0, dist_base + GIC_DIST_IGROUP + 0); + pr_debug("gic: FIQ support %s\n", + gic->fiq_enable ? "enabled" : "disabled"); + + if (!gic->fiq_enable) + return; +} +#else /* CONFIG_FIQ */ +static inline void gic_init_fiq(struct gic_chip_data *gic, + irq_hw_number_t first_irq, + unsigned int num_irqs) {} +#endif /* CONFIG_FIQ */ + void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) { if (gic_nr >= MAX_GIC_NR) @@ -373,7 +425,22 @@ static void __init gic_dist_init(struct gic_chip_data *gic) gic_dist_config(base, gic_irqs, NULL); - writel_relaxed(1, base + GIC_DIST_CTRL); + /* + * Optionally set all global interrupts to be group 1. + */ + if (gic_data_fiq_enable(gic)) + for (i = 32; i < gic_irqs; i += 32) + writel_relaxed(0xffffffff, + base + GIC_DIST_IGROUP + i * 4 / 32); + + /* + * Set EnableGrp1/EnableGrp0 (bit 1 and 0) or EnableGrp (bit 0 only, + * bit 1 ignored) + */ + if (gic_data_fiq_enable(gic)) + writel_relaxed(3, base + GIC_DIST_CTRL); + else + writel_relaxed(1, base + GIC_DIST_CTRL); } static void gic_cpu_init(struct gic_chip_data *gic) @@ -400,8 +467,20 @@ static void gic_cpu_init(struct gic_chip_data *gic) gic_cpu_config(dist_base, NULL); + /* + * Set all PPI and SGI interrupts to be group 1. + * + * If grouping is not available (not implemented or prohibited by + * security mode) these registers are read-as-zero/write-ignored. + */ + if (gic_data_fiq_enable(gic)) + writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + 0); + writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); - writel_relaxed(1, base + GIC_CPU_CTRL); + if (gic_data_fiq_enable(gic)) + writel_relaxed(0x1f, base + GIC_CPU_CTRL); + else + writel_relaxed(1, base + GIC_CPU_CTRL); } void gic_cpu_if_down(void) @@ -485,7 +564,10 @@ static void gic_dist_restore(unsigned int gic_nr) writel_relaxed(gic_data[gic_nr].saved_spi_enable[i], dist_base + GIC_DIST_ENABLE_SET + i * 4); - writel_relaxed(1, dist_base + GIC_DIST_CTRL); + if (gic_data_fiq_enable(&gic_data[gic_nr])) + writel_relaxed(3, dist_base + GIC_DIST_CTRL); + else + writel_relaxed(1, dist_base + GIC_DIST_CTRL); } static void gic_cpu_save(unsigned int gic_nr) @@ -542,7 +624,7 @@ static void gic_cpu_restore(unsigned int gic_nr) writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4); writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK); - writel_relaxed(1, cpu_base + GIC_CPU_CTRL); + writel_relaxed(0x1f, cpu_base + GIC_CPU_CTRL); } static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v) @@ -604,6 +686,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) { int cpu; unsigned long flags, map = 0; + unsigned long softint; raw_spin_lock_irqsave(&irq_controller_lock, flags); @@ -618,7 +701,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) dmb(ishst); /* this always happens on GIC0 */ - writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); + softint = map << 16 | irq; + if (gic_data_fiq_enable(&gic_data[0])) + softint |= 0x8000; + writel_relaxed(softint, + gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); raw_spin_unlock_irqrestore(&irq_controller_lock, flags); } @@ -964,6 +1051,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, hwirq_base, &gic_irq_domain_ops, gic); + + gic_init_fiq(gic, irq_base, gic_irqs); } else { gic->domain = irq_domain_add_linear(node, nr_routable_irqs, &gic_irq_domain_ops,