From patchwork Tue Sep 2 13:00:45 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Thompson X-Patchwork-Id: 4825461 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 EF83B9F3FA for ; Tue, 2 Sep 2014 13:08:06 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E2225201CE for ; Tue, 2 Sep 2014 13:08:01 +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 43CC8201CD for ; Tue, 2 Sep 2014 13:08:00 +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 1XOnl4-000126-E6; Tue, 02 Sep 2014 13:04:26 +0000 Received: from mail-wi0-f173.google.com ([209.85.212.173]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XOnkg-0000ae-GL for linux-arm-kernel@lists.infradead.org; Tue, 02 Sep 2014 13:04:03 +0000 Received: by mail-wi0-f173.google.com with SMTP id cc10so7376444wib.12 for ; Tue, 02 Sep 2014 06:03:40 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=aWWdlJH+0kd+HP+pOEQIDWZQd8Ef5aMj3kuA5mXOLpU=; b=F76W4nqxITKyMrAxJtpSDYrXQnRzmHZAP/kROOsv3qrVPeUkGbyqL6aWHGOdXt+smR Z6s96aWcCE047aoJNtpYmZAxB2ypivaaL+Grb2YdBlOgpcs/tzS9ZBg8QklR/Gx70gLB 63zvzI9Ly3oWB1g3j4xK5EZuv8GPFpGkhPgnsBCbRZWaEm6OTFrPRV/OgBJP3QcYjNMC 1ZR+PGuxTms99oDc46JMblwASeBlU9wTgRtTVmh9Frbdph8l/FJQzPe4UoKXl+bbPgZQ Z53FxWKgH82taSt99QxvSF+QYXbenWLlsHHpY6j2XBFyhv8nVdqcvpBreVTtBhlrndx3 mg0Q== X-Gm-Message-State: ALoCoQnlwci31KCgS1wfLBwumABgcGyE3N5z2mjnwICBRTVpmrJXxDNI0eZEhIs5C3RN6+VvP+Ut X-Received: by 10.180.91.70 with SMTP id cc6mr28579881wib.66.1409663020371; Tue, 02 Sep 2014 06:03:40 -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.38 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 02 Sep 2014 06:03:39 -0700 (PDT) From: Daniel Thompson To: Russell King Subject: [PATCH v11 11/19] irqchip: vic: Add support for FIQ management Date: Tue, 2 Sep 2014 14:00:45 +0100 Message-Id: <1409662853-29313-12-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-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140902_060402_846520_E560BFB1 X-CRM114-Status: GOOD ( 26.14 ) X-Spam-Score: -0.7 (/) Cc: Catalin Marinas , Linus Walleij , Fabio Estevam , Daniel Thompson , Kukjin Kim , Nicolas Pitre , Anton Vorontsov , Ben Dooks , kgdb-bugreport@lists.sourceforge.net, kernel-team@android.com, Dave Martin , linaro-kernel@lists.linaro.org, Jason Cooper , patches@linaro.org, linux-samsung-soc@vger.kernel.org, John Stultz , Ben Dooks , Thomas Gleixner , linux-arm-kernel@lists.infradead.org, Ryan Mallon , linux-kernel@vger.kernel.org, Hartley Sweeten , Colin Cross , Frederic Weisbecker 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=-3.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable 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 This patch introduces callbacks to route interrupts to or away from the FIQ signal. It also causes these callbacks to be registered with the FIQ infrastructure. This patch enable FIQ support for mach-versatile whilst mach-ep93xx, mach-netx, mach-s3c64xx and plat-samsung are unmodified (and can therefore continue to use init_FIQ() as before). Signed-off-by: Daniel Thompson Cc: Hartley Sweeten Cc: Ryan Mallon Cc: Russell King Cc: Ben Dooks Cc: Kukjin Kim Cc: Thomas Gleixner Cc: Jason Cooper Cc: linux-samsung-soc@vger.kernel.org --- arch/arm/mach-versatile/core.c | 2 +- drivers/irqchip/irq-gic.c | 21 ++++------ drivers/irqchip/irq-vic.c | 92 ++++++++++++++++++++++++++++++++--------- include/linux/irqchip/arm-gic.h | 3 ++ include/linux/irqchip/arm-vic.h | 6 ++- 5 files changed, 88 insertions(+), 36 deletions(-) diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 08fb8c8..bad1d30 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -108,7 +108,7 @@ void __init versatile_init_irq(void) np = of_find_matching_node_by_address(NULL, vic_of_match, VERSATILE_VIC_BASE); - __vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np); + __vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np ? false : true, np); writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index bda5a91..8821160 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -502,13 +502,17 @@ static void __init gic_init_fiq(struct gic_chip_data *gic, /* * Fully acknowledge (both ack and eoi) a FIQ-based IPI */ -static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs, - void *data) +void gic_handle_fiq_ipi(void) { struct gic_chip_data *gic = &gic_data[0]; - void __iomem *cpu_base = gic_data_cpu_base(gic); + void __iomem *cpu_base; unsigned long irqstat, irqnr; + if (!gic || !gic->fiq_enable) + return; + + cpu_base = gic_data_cpu_base(gic); + if (WARN_ON(!in_nmi())) return NOTIFY_BAD; @@ -525,13 +529,6 @@ static int gic_handle_fiq_ipi(struct notifier_block *nb, unsigned long regs, return NOTIFY_OK; } - -/* - * Notifier to ensure IPI FIQ is acknowledged correctly. - */ -static struct notifier_block gic_fiq_ipi_notifier = { - .notifier_call = gic_handle_fiq_ipi, -}; #else /* CONFIG_FIQ */ static inline void gic_set_group_irq(void __iomem *base, unsigned int hwirq, int group) {} @@ -1250,10 +1247,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, #ifdef CONFIG_SMP set_smp_cross_call(gic_raise_softirq); register_cpu_notifier(&gic_cpu_notifier); -#ifdef CONFIG_FIQ - if (gic_data_fiq_enable(gic)) - register_fiq_nmi_notifier(&gic_fiq_ipi_notifier); -#endif #endif set_handle_irq(gic_handle_irq); } diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index 7d35287..22aa126 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -36,6 +36,9 @@ #include #include +#ifdef CONFIG_FIQ +#include +#endif #include "irqchip.h" @@ -261,11 +264,53 @@ static struct irq_domain_ops vic_irqdomain_ops = { .xlate = irq_domain_xlate_onetwocell, }; +#ifdef CONFIG_FIQ +static DEFINE_RAW_SPINLOCK(irq_controller_lock); + +static void vic_set_fiq(struct irq_data *d, bool enable) +{ + void __iomem *base = irq_data_get_irq_chip_data(d); + unsigned int irq = d->hwirq; + u32 val; + + raw_spin_lock(&irq_controller_lock); + val = readl(base + VIC_INT_SELECT); + if (enable) + val |= 1 << irq; + else + val &= ~(1 << irq); + writel(val, base + VIC_INT_SELECT); + raw_spin_unlock(&irq_controller_lock); +} + +static void vic_enable_fiq(struct irq_data *d) +{ + vic_set_fiq(d, true); +} + +static void vic_disable_fiq(struct irq_data *d) +{ + vic_set_fiq(d, false); +} + +struct fiq_chip vic_fiq = { + .fiq_enable = vic_enable_fiq, + .fiq_disable = vic_disable_fiq, +}; + +static void vic_register_fiq(int irq) +{ + fiq_register_mapping(irq, &vic_fiq); +} +#else /* CONFIG_FIQ */ +static inline void vic_register_fiq(int irq) {} +#endif /* CONFIG_FIQ */ + /** * vic_register() - Register a VIC. * @base: The base address of the VIC. * @parent_irq: The parent IRQ if cascaded, else 0. - * @irq: The base IRQ for the VIC. + * @irq_start: The base IRQ for the VIC. * @valid_sources: bitmask of valid interrupts * @resume_sources: bitmask of interrupts allowed for resume sources. * @node: The device tree node associated with the VIC. @@ -277,12 +322,13 @@ static struct irq_domain_ops vic_irqdomain_ops = { * This also configures the IRQ domain for the VIC. */ static void __init vic_register(void __iomem *base, unsigned int parent_irq, - unsigned int irq, + unsigned int irq_start, u32 valid_sources, u32 resume_sources, - struct device_node *node) + bool map_fiqs, struct device_node *node) { struct vic_device *v; int i; + unsigned int irq; if (vic_id >= ARRAY_SIZE(vic_devices)) { printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__); @@ -301,15 +347,19 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq, irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded); } - v->domain = irq_domain_add_simple(node, fls(valid_sources), irq, + v->domain = irq_domain_add_simple(node, fls(valid_sources), irq_start, &vic_irqdomain_ops, v); /* create an IRQ mapping for each valid IRQ */ - for (i = 0; i < fls(valid_sources); i++) - if (valid_sources & (1 << i)) - irq_create_mapping(v->domain, i); + for (i = 0; i < fls(valid_sources); i++) { + if (valid_sources & (1 << i)) { + irq = irq_create_mapping(v->domain, i); + vic_register_fiq(irq); + } + } + /* If no base IRQ was passed, figure out our allocated base */ - if (irq) - v->irq = irq; + if (irq_start) + v->irq = irq_start; else v->irq = irq_find_mapping(v->domain, 0); } @@ -413,7 +463,8 @@ static void __init vic_clear_interrupts(void __iomem *base) * and 020 within the page. We call this "second block". */ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, - u32 vic_sources, struct device_node *node) + u32 vic_sources, bool map_fiqs, + struct device_node *node) { unsigned int i; int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0; @@ -439,12 +490,12 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, writel(32, base + VIC_PL190_DEF_VECT_ADDR); } - vic_register(base, 0, irq_start, vic_sources, 0, node); + vic_register(base, 0, irq_start, vic_sources, 0, map_fiqs, node); } void __init __vic_init(void __iomem *base, int parent_irq, int irq_start, - u32 vic_sources, u32 resume_sources, - struct device_node *node) + u32 vic_sources, u32 resume_sources, + bool map_fiqs, struct device_node *node) { unsigned int i; u32 cellid = 0; @@ -462,7 +513,7 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start, switch(vendor) { case AMBA_VENDOR_ST: - vic_init_st(base, irq_start, vic_sources, node); + vic_init_st(base, irq_start, vic_sources, map_fiqs, node); return; default: printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n"); @@ -479,7 +530,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start, vic_init2(base); - vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node); + vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, + map_fiqs, node); } /** @@ -492,7 +544,8 @@ void __init __vic_init(void __iomem *base, int parent_irq, int irq_start, void __init vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources) { - __vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL); + __vic_init(base, 0, irq_start, vic_sources, resume_sources, + false, NULL); } /** @@ -511,7 +564,8 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq, struct vic_device *v; v = &vic_devices[vic_id]; - __vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL); + __vic_init(base, parent_irq, 0, vic_sources, resume_sources, false, + NULL); /* Return out acquired base */ return v->irq; } @@ -535,9 +589,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent) of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask); /* - * Passing 0 as first IRQ makes the simple domain allocate descriptors + * Passing 0 as first IRQ makes the domain allocate descriptors. */ - __vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node); + __vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, true, node); return 0; } diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 45e2d8c..52a5676 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -101,5 +101,8 @@ static inline void __init register_routable_domain_ops { gic_routable_irq_domain_ops = ops; } + +void gic_handle_fiq_ipi(void); + #endif /* __ASSEMBLY */ #endif diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h index ba46c79..30ab39f 100644 --- a/include/linux/irqchip/arm-vic.h +++ b/include/linux/irqchip/arm-vic.h @@ -30,8 +30,10 @@ struct device_node; struct pt_regs; void __vic_init(void __iomem *base, int parent_irq, int irq_start, - u32 vic_sources, u32 resume_sources, struct device_node *node); -void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources); + u32 vic_sources, u32 resume_sources, + bool map_fiqs, struct device_node *node); +void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, + u32 resume_sources); int vic_init_cascaded(void __iomem *base, unsigned int parent_irq, u32 vic_sources, u32 resume_sources);