From db4c4426daedffefcfd890d04a6ec9ed93268878 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 28 Jan 2016 12:52:33 +0530 Subject: ARC: [intc-compact] setup TIMER as percpu_dev This removes the quirk from arc_request_percpu_irq() and paves way for future simplifications Signed-off-by: Vineet Gupta --- arch/arc/kernel/irq.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'arch/arc/kernel/irq.c') diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index ba17f85285cf..88074b50456b 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c @@ -72,18 +72,6 @@ void arc_request_percpu_irq(int irq, int cpu, if (!cpu) { int rc; -#ifdef CONFIG_ISA_ARCOMPACT - /* - * A subsequent request_percpu_irq() fails if percpu_devid is - * not set. That in turns sets NOAUTOEN, meaning each core needs - * to call enable_percpu_irq() - * - * For ARCv2, this is done in irq map function since we know - * which irqs are strictly per cpu - */ - irq_set_percpu_devid(irq); -#endif - rc = request_percpu_irq(irq, isr, irq_nm, percpu_dev); if (rc) panic("Percpu IRQ request failed for %d\n", irq); -- cgit v1.2.3 From 569579401ae1c9b9f317f38261e32135b153e9b3 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 28 Jan 2016 12:56:03 +0530 Subject: ARC: opencode arc_request_percpu_irq - The idea is to remove the API usage since it has a subltle design flaw - relies on being called on cpu0 first. This is true for some early per cpu irqs such as TIMER/IPI, but not for late probed per cpu peripherals such a perf. And it's usage in perf has already bitten us once: see c6317bc7c5ab ("ARCv2: perf: Ensure perf intr gets enabled on all cores") where we ended up open coding it anyways - The seeming duplication will go away once we start using cpu notifier for timer setup Signed-off-by: Vineet Gupta --- arch/arc/include/asm/irq.h | 3 --- arch/arc/kernel/irq.c | 29 ----------------------------- arch/arc/kernel/smp.c | 15 ++++++++++++++- arch/arc/kernel/time.c | 14 +++++++++++--- 4 files changed, 25 insertions(+), 36 deletions(-) (limited to 'arch/arc/kernel/irq.c') diff --git a/arch/arc/include/asm/irq.h b/arch/arc/include/asm/irq.h index 49014f0ef36d..f9c735ede4fc 100644 --- a/arch/arc/include/asm/irq.h +++ b/arch/arc/include/asm/irq.h @@ -26,8 +26,5 @@ extern void arc_init_IRQ(void); void arc_local_timer_setup(void); -void arc_request_percpu_irq(int irq, int cpu, - irqreturn_t (*isr)(int irq, void *dev), - const char *irq_nm, void *percpu_dev); #endif diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index 88074b50456b..fb6dede9d05f 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c @@ -50,32 +50,3 @@ void arch_do_IRQ(unsigned int irq, struct pt_regs *regs) irq_exit(); set_irq_regs(old_regs); } - -/* - * API called for requesting percpu interrupts - called by each CPU - * - For boot CPU, actually request the IRQ with genirq core + enables - * - For subsequent callers only enable called locally - * - * Relies on being called by boot cpu first (i.e. request called ahead) of - * any enable as expected by genirq. Hence Suitable only for TIMER, IPI - * which are guaranteed to be setup on boot core first. - * Late probed peripherals such as perf can't use this as there no guarantee - * of being called on boot CPU first. - */ - -void arc_request_percpu_irq(int irq, int cpu, - irqreturn_t (*isr)(int irq, void *dev), - const char *irq_nm, - void *percpu_dev) -{ - /* Boot cpu calls request, all call enable */ - if (!cpu) { - int rc; - - rc = request_percpu_irq(irq, isr, irq_nm, percpu_dev); - if (rc) - panic("Percpu IRQ request failed for %d\n", irq); - } - - enable_percpu_irq(irq, 0); -} diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index 4cb3add77c75..ca83ebe15a64 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -346,6 +346,10 @@ irqreturn_t do_IPI(int irq, void *dev_id) /* * API called by platform code to hookup arch-common ISR to their IPI IRQ + * + * Note: If IPI is provided by platform (vs. say ARC MCIP), their intc setup/map + * function needs to call call irq_set_percpu_devid() for IPI IRQ, otherwise + * request_percpu_irq() below will fail */ static DEFINE_PER_CPU(int, ipi_dev); @@ -353,7 +357,16 @@ int smp_ipi_irq_setup(int cpu, int irq) { int *dev = per_cpu_ptr(&ipi_dev, cpu); - arc_request_percpu_irq(irq, cpu, do_IPI, "IPI Interrupt", dev); + /* Boot cpu calls request, all call enable */ + if (!cpu) { + int rc; + + rc = request_percpu_irq(irq, do_IPI, "IPI Interrupt", dev); + if (rc) + panic("Percpu IRQ request failed for %d\n", irq); + } + + enable_percpu_irq(irq, 0); return 0; } diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c index 7d9a736fc7e5..146da3cbcc99 100644 --- a/arch/arc/kernel/time.c +++ b/arch/arc/kernel/time.c @@ -251,14 +251,22 @@ void arc_local_timer_setup() { struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); int cpu = smp_processor_id(); + int irq = TIMER0_IRQ; evt->cpumask = cpumask_of(cpu); clockevents_config_and_register(evt, arc_get_core_freq(), 0, ARC_TIMER_MAX); - /* setup the per-cpu timer IRQ handler - for all cpus */ - arc_request_percpu_irq(TIMER0_IRQ, cpu, timer_irq_handler, - "Timer0 (per-cpu-tick)", evt); + if (!cpu) { + int rc; + + rc = request_percpu_irq(irq, timer_irq_handler, + "Timer0 (per-cpu-tick)", evt); + if (rc) + panic("Percpu IRQ request failed for TIMER\n"); + } + + enable_percpu_irq(irq, 0); } /* -- cgit v1.2.3 From 1b0ccb8a4eee2d8c14adc996e07335cb7aa9e2ac Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Fri, 1 Jan 2016 15:12:54 +0530 Subject: ARC: [intc-*] Do a domain lookup in primary handler for hwirq -> linux virq The primary interrupt handler arch_do_IRQ() was passing hwirq as linux virq to core code. This was fragile and worked so far as we only had legacy/linear domains. This came out of a rant by Marc Zyngier. http://lists.infradead.org/pipermail/linux-snps-arc/2015-December/000298.html Cc: Marc Zyngier Cc: Thomas Gleixner Cc: Noam Camus Signed-off-by: Vineet Gupta --- arch/arc/Kconfig | 1 + arch/arc/kernel/intc-arcv2.c | 9 ++++++--- arch/arc/kernel/intc-compact.c | 10 ++++++---- arch/arc/kernel/irq.c | 9 ++------- 4 files changed, 15 insertions(+), 14 deletions(-) (limited to 'arch/arc/kernel/irq.c') diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index ae3943435abf..4f1482aa8823 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -31,6 +31,7 @@ config ARC select HAVE_MOD_ARCH_SPECIFIC if ARC_DW2_UNWIND select HAVE_OPROFILE select HAVE_PERF_EVENTS + select HANDLE_DOMAIN_IRQ select IRQ_DOMAIN select MODULES_USE_ELF_RELA select NO_BOOTMEM diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index 942526322ae7..592cc977151e 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -137,21 +137,24 @@ static const struct irq_domain_ops arcv2_irq_ops = { .map = arcv2_irq_map, }; -static struct irq_domain *root_domain; static int __init init_onchip_IRQ(struct device_node *intc, struct device_node *parent) { + struct irq_domain *root_domain; + if (parent) panic("DeviceTree incore intc not a root irq controller\n"); root_domain = irq_domain_add_legacy(intc, NR_CPU_IRQS, 0, 0, &arcv2_irq_ops, NULL); - if (!root_domain) panic("root irq domain not avail\n"); - /* with this we don't need to export root_domain */ + /* + * Needed for primary domain lookup to succeed + * This is a primary irqchip, and can never have a parent + */ irq_set_default_host(root_domain); return 0; diff --git a/arch/arc/kernel/intc-compact.c b/arch/arc/kernel/intc-compact.c index d31bc647146d..48a8b24de23e 100644 --- a/arch/arc/kernel/intc-compact.c +++ b/arch/arc/kernel/intc-compact.c @@ -97,21 +97,23 @@ static const struct irq_domain_ops arc_intc_domain_ops = { .map = arc_intc_domain_map, }; -static struct irq_domain *root_domain; - static int __init init_onchip_IRQ(struct device_node *intc, struct device_node *parent) { + struct irq_domain *root_domain; + if (parent) panic("DeviceTree incore intc not a root irq controller\n"); root_domain = irq_domain_add_legacy(intc, NR_CPU_IRQS, 0, 0, &arc_intc_domain_ops, NULL); - if (!root_domain) panic("root irq domain not avail\n"); - /* with this we don't need to export root_domain */ + /* + * Needed for primary domain lookup to succeed + * This is a primary irqchip, and can never have a parent + */ irq_set_default_host(root_domain); return 0; diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index fb6dede9d05f..538b36afe89e 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c @@ -41,12 +41,7 @@ void __init init_IRQ(void) * "C" Entry point for any ARC ISR, called from low level vector handler * @irq is the vector number read from ICAUSE reg of on-chip intc */ -void arch_do_IRQ(unsigned int irq, struct pt_regs *regs) +void arch_do_IRQ(unsigned int hwirq, struct pt_regs *regs) { - struct pt_regs *old_regs = set_irq_regs(regs); - - irq_enter(); - generic_handle_irq(irq); - irq_exit(); - set_irq_regs(old_regs); + handle_domain_irq(NULL, hwirq, regs); } -- cgit v1.2.3