From 1e77d0a1ed7417d2a5a52a7b8d32aea1833faa6c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 7 Mar 2013 14:53:45 +0100 Subject: genirq: Sanitize spurious interrupt detection of threaded irqs Till reported that the spurious interrupt detection of threaded interrupts is broken in two ways: - note_interrupt() is called for each action thread of a shared interrupt line. That's wrong as we are only interested whether none of the device drivers felt responsible for the interrupt, but by calling multiple times for a single interrupt line we account IRQ_NONE even if one of the drivers felt responsible. - note_interrupt() when called from the thread handler is not serialized. That leaves the members of irq_desc which are used for the spurious detection unprotected. To solve this we need to defer the spurious detection of a threaded interrupt to the next hardware interrupt context where we have implicit serialization. If note_interrupt is called with action_ret == IRQ_WAKE_THREAD, we check whether the previous interrupt requested a deferred check. If not, we request a deferred check for the next hardware interrupt and return. If set, we check whether one of the interrupt threads signaled success. Depending on this information we feed the result into the spurious detector. If one primary handler of a shared interrupt returns IRQ_HANDLED we disable the deferred check of irq threads on the same line, as we have found at least one device driver who cared. Reported-by: Till Straumann Signed-off-by: Thomas Gleixner Tested-by: Austin Schuh Cc: Oliver Hartkopp Cc: Wolfgang Grandegger Cc: Pavel Pisa Cc: Marc Kleine-Budde Cc: linux-can@vger.kernel.org Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/alpine.LFD.2.02.1303071450130.22263@ionos diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 26e2661..472c021 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -27,6 +27,8 @@ struct irq_desc; * @irq_count: stats field to detect stalled irqs * @last_unhandled: aging timer for unhandled count * @irqs_unhandled: stats field for spurious unhandled interrupts + * @threads_handled: stats field for deferred spurious detection of threaded handlers + * @threads_handled_last: comparator field for deferred spurious detection of theraded handlers * @lock: locking for SMP * @affinity_hint: hint to user space for preferred irq affinity * @affinity_notify: context for notification of affinity changes @@ -52,6 +54,8 @@ struct irq_desc { unsigned int irq_count; /* For detecting broken IRQs */ unsigned long last_unhandled; /* Aging timer for unhandled count */ unsigned int irqs_unhandled; + atomic_t threads_handled; + int threads_handled_last; raw_spinlock_t lock; struct cpumask *percpu_enabled; #ifdef CONFIG_SMP diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index d34131c..3dc6a61 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -886,8 +886,8 @@ static int irq_thread(void *data) irq_thread_check_affinity(desc, action); action_ret = handler_fn(desc, action); - if (!noirqdebug) - note_interrupt(action->irq, desc, action_ret); + if (action_ret == IRQ_HANDLED) + atomic_inc(&desc->threads_handled); wake_threads_waitq(desc); } diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index a1d8cc6..e2514b0 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -270,6 +270,8 @@ try_misrouted_irq(unsigned int irq, struct irq_desc *desc, return action && (action->flags & IRQF_IRQPOLL); } +#define SPURIOUS_DEFERRED 0x80000000 + void note_interrupt(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret) { @@ -277,15 +279,111 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc, irq_settings_is_polled(desc)) return; - /* we get here again via the threaded handler */ - if (action_ret == IRQ_WAKE_THREAD) - return; - if (bad_action_ret(action_ret)) { report_bad_irq(irq, desc, action_ret); return; } + /* + * We cannot call note_interrupt from the threaded handler + * because we need to look at the compound of all handlers + * (primary and threaded). Aside of that in the threaded + * shared case we have no serialization against an incoming + * hardware interrupt while we are dealing with a threaded + * result. + * + * So in case a thread is woken, we just note the fact and + * defer the analysis to the next hardware interrupt. + * + * The threaded handlers store whether they sucessfully + * handled an interrupt and we check whether that number + * changed versus the last invocation. + * + * We could handle all interrupts with the delayed by one + * mechanism, but for the non forced threaded case we'd just + * add pointless overhead to the straight hardirq interrupts + * for the sake of a few lines less code. + */ + if (action_ret & IRQ_WAKE_THREAD) { + /* + * There is a thread woken. Check whether one of the + * shared primary handlers returned IRQ_HANDLED. If + * not we defer the spurious detection to the next + * interrupt. + */ + if (action_ret == IRQ_WAKE_THREAD) { + int handled; + /* + * We use bit 31 of thread_handled_last to + * denote the deferred spurious detection + * active. No locking necessary as + * thread_handled_last is only accessed here + * and we have the guarantee that hard + * interrupts are not reentrant. + */ + if (!(desc->threads_handled_last & SPURIOUS_DEFERRED)) { + desc->threads_handled_last |= SPURIOUS_DEFERRED; + return; + } + /* + * Check whether one of the threaded handlers + * returned IRQ_HANDLED since the last + * interrupt happened. + * + * For simplicity we just set bit 31, as it is + * set in threads_handled_last as well. So we + * avoid extra masking. And we really do not + * care about the high bits of the handled + * count. We just care about the count being + * different than the one we saw before. + */ + handled = atomic_read(&desc->threads_handled); + handled |= SPURIOUS_DEFERRED; + if (handled != desc->threads_handled_last) { + action_ret = IRQ_HANDLED; + /* + * Note: We keep the SPURIOUS_DEFERRED + * bit set. We are handling the + * previous invocation right now. + * Keep it for the current one, so the + * next hardware interrupt will + * account for it. + */ + desc->threads_handled_last = handled; + } else { + /* + * None of the threaded handlers felt + * responsible for the last interrupt + * + * We keep the SPURIOUS_DEFERRED bit + * set in threads_handled_last as we + * need to account for the current + * interrupt as well. + */ + action_ret = IRQ_NONE; + } + } else { + /* + * One of the primary handlers returned + * IRQ_HANDLED. So we don't care about the + * threaded handlers on the same line. Clear + * the deferred detection bit. + * + * In theory we could/should check whether the + * deferred bit is set and take the result of + * the previous run into account here as + * well. But it's really not worth the + * trouble. If every other interrupt is + * handled we never trigger the spurious + * detector. And if this is just the one out + * of 100k unhandled ones which is handled + * then we merily delay the spurious detection + * by one hard interrupt. Not a real problem. + */ + desc->threads_handled_last &= ~SPURIOUS_DEFERRED; + } + } + if (unlikely(action_ret == IRQ_NONE)) { /* * If we are seeing only the odd spurious IRQ caused by -- cgit v0.10.2 From 37ebbcff78375bfa69eb69748ef00f577b7c1c6c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:04 +0000 Subject: arm: iop13xx: Use sparse irqs for MSI No need for a private allocator. The core code handles it already. Allocate the non MSI irqs right at boot time via machine_desc->nr_irqs and let the sparse core handle the MSI space. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: Dan Williams Cc: Russell King Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/20140507154333.809210026@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index db3c541..a2c1a18 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -480,6 +480,7 @@ config ARCH_IOP13XX select PCI select PLAT_IOP select VMSPLIT_1G + select SPARSE_IRQ help Support for Intel's IOP13XX (XScale) family of processors. diff --git a/arch/arm/mach-iop13xx/include/mach/irqs.h b/arch/arm/mach-iop13xx/include/mach/irqs.h index 054e7ac..e8d24d3 100644 --- a/arch/arm/mach-iop13xx/include/mach/irqs.h +++ b/arch/arm/mach-iop13xx/include/mach/irqs.h @@ -191,6 +191,4 @@ static inline u32 read_intpnd_3(void) #define NR_IOP13XX_IRQS (IRQ_IOP13XX_HPI + 1) #endif -#define NR_IRQS NR_IOP13XX_IRQS - #endif /* _IOP13XX_IRQ_H_ */ diff --git a/arch/arm/mach-iop13xx/include/mach/time.h b/arch/arm/mach-iop13xx/include/mach/time.h index f1c00d6..15bc9bb 100644 --- a/arch/arm/mach-iop13xx/include/mach/time.h +++ b/arch/arm/mach-iop13xx/include/mach/time.h @@ -1,5 +1,8 @@ #ifndef _IOP13XX_TIME_H_ #define _IOP13XX_TIME_H_ + +#include + #define IRQ_IOP_TIMER0 IRQ_IOP13XX_TIMER0 #define IOP_TMR_EN 0x02 diff --git a/arch/arm/mach-iop13xx/iq81340mc.c b/arch/arm/mach-iop13xx/iq81340mc.c index 02a8228..9cd07d3 100644 --- a/arch/arm/mach-iop13xx/iq81340mc.c +++ b/arch/arm/mach-iop13xx/iq81340mc.c @@ -93,4 +93,5 @@ MACHINE_START(IQ81340MC, "Intel IQ81340MC") .init_time = iq81340mc_timer_init, .init_machine = iq81340mc_init, .restart = iop13xx_restart, + .nr_irqs = NR_IOP13XX_IRQS, MACHINE_END diff --git a/arch/arm/mach-iop13xx/iq81340sc.c b/arch/arm/mach-iop13xx/iq81340sc.c index 1b80f10..b3ec11c 100644 --- a/arch/arm/mach-iop13xx/iq81340sc.c +++ b/arch/arm/mach-iop13xx/iq81340sc.c @@ -95,4 +95,5 @@ MACHINE_START(IQ81340SC, "Intel IQ81340SC") .init_time = iq81340sc_timer_init, .init_machine = iq81340sc_init, .restart = iop13xx_restart, + .nr_irqs = NR_IOP13XX_IRQS, MACHINE_END diff --git a/arch/arm/mach-iop13xx/msi.c b/arch/arm/mach-iop13xx/msi.c index 560d5b2..655072d 100644 --- a/arch/arm/mach-iop13xx/msi.c +++ b/arch/arm/mach-iop13xx/msi.c @@ -24,10 +24,6 @@ #include #include - -#define IOP13XX_NUM_MSI_IRQS 128 -static DECLARE_BITMAP(msi_irq_in_use, IOP13XX_NUM_MSI_IRQS); - /* IMIPR0 CP6 R8 Page 1 */ static u32 read_imipr_0(void) @@ -121,41 +117,6 @@ void __init iop13xx_msi_init(void) irq_set_chained_handler(IRQ_IOP13XX_INBD_MSI, iop13xx_msi_handler); } -/* - * Dynamic irq allocate and deallocation - */ -int create_irq(void) -{ - int irq, pos; - -again: - pos = find_first_zero_bit(msi_irq_in_use, IOP13XX_NUM_MSI_IRQS); - irq = IRQ_IOP13XX_MSI_0 + pos; - if (irq > NR_IRQS) - return -ENOSPC; - /* test_and_set_bit operates on 32-bits at a time */ - if (test_and_set_bit(pos, msi_irq_in_use)) - goto again; - - dynamic_irq_init(irq); - - return irq; -} - -void destroy_irq(unsigned int irq) -{ - int pos = irq - IRQ_IOP13XX_MSI_0; - - dynamic_irq_cleanup(irq); - - clear_bit(pos, msi_irq_in_use); -} - -void arch_teardown_msi_irq(unsigned int irq) -{ - destroy_irq(irq); -} - static void iop13xx_msi_nop(struct irq_data *d) { return; @@ -172,12 +133,17 @@ static struct irq_chip iop13xx_msi_chip = { int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) { - int id, irq = create_irq(); + int id, irq = irq_alloc_desc_from(IRQ_IOP13XX_MSI_0, -1); struct msi_msg msg; if (irq < 0) return irq; + if (irq >= NR_IOP13XX_IRQS) { + irq_free_desc(irq); + return -ENOSPC; + } + irq_set_msi_desc(irq, desc); msg.address_hi = 0x0; @@ -191,3 +157,8 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) return 0; } + +void arch_teardown_msi_irq(unsigned int irq) +{ + irq_free_desc(irq); +} diff --git a/arch/arm/mach-iop13xx/setup.c b/arch/arm/mach-iop13xx/setup.c index 96e6c7a..bca96f4 100644 --- a/arch/arm/mach-iop13xx/setup.c +++ b/arch/arm/mach-iop13xx/setup.c @@ -27,6 +27,7 @@ #include #include #include +#include #define IOP13XX_UART_XTAL 33334000 #define IOP13XX_SETUP_DEBUG 0 diff --git a/arch/arm/mach-iop13xx/tpmi.c b/arch/arm/mach-iop13xx/tpmi.c index 6fdad7a..db511ec 100644 --- a/arch/arm/mach-iop13xx/tpmi.c +++ b/arch/arm/mach-iop13xx/tpmi.c @@ -24,6 +24,7 @@ #include #include #include +#include /* assumes CONTROLLER_ONLY# is never asserted in the ESSR register */ #define IOP13XX_TPMI_MMR(dev) IOP13XX_REG_ADDR32_PHYS(0x48000 + (dev << 12)) -- cgit v0.10.2 From 465665f78a7f47d46d7fe18195f3548b4911547f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:05 +0000 Subject: mips: Kill pointless destroy_irq() Copy and paste leftovers with no functionality at all. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: Ralf Baechle Cc: Jayachandran C Cc: linux-mips@linux-mips.org Link: http://lkml.kernel.org/r/20140507154334.008113902@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/mips/pci/msi-xlp.c b/arch/mips/pci/msi-xlp.c index afd8405..3249685 100644 --- a/arch/mips/pci/msi-xlp.c +++ b/arch/mips/pci/msi-xlp.c @@ -206,14 +206,8 @@ static struct irq_chip xlp_msix_chip = { .irq_unmask = unmask_msi_irq, }; -void destroy_irq(unsigned int irq) -{ - /* nothing to do yet */ -} - void arch_teardown_msi_irq(unsigned int irq) { - destroy_irq(irq); } /* @@ -298,10 +292,8 @@ static int xlp_setup_msi(uint64_t lnkbase, int node, int link, xirq = xirq + msivec; /* msi mapped to global irq space */ ret = irq_set_msi_desc(xirq, desc); - if (ret < 0) { - destroy_irq(xirq); + if (ret < 0) return ret; - } write_msi_msg(xirq, &msg); return 0; diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c index 4427abb..0dde803 100644 --- a/arch/mips/pci/pci-xlr.c +++ b/arch/mips/pci/pci-xlr.c @@ -214,14 +214,8 @@ static int get_irq_vector(const struct pci_dev *dev) } #ifdef CONFIG_PCI_MSI -void destroy_irq(unsigned int irq) -{ - /* nothing to do yet */ -} - void arch_teardown_msi_irq(unsigned int irq) { - destroy_irq(irq); } int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) @@ -263,10 +257,8 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) MSI_DATA_DELIVERY_FIXED; ret = irq_set_msi_desc(irq, desc); - if (ret < 0) { - destroy_irq(irq); + if (ret < 0) return ret; - } write_msi_msg(irq, &msg); return 0; -- cgit v0.10.2 From 7b6ef1262549f6afc5c881aaef80beb8fd15f908 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:05 +0000 Subject: genirq: Provide generic hwirq allocation facility Not really the solution to the problem, but at least it confines the mess in the core code and allows to get rid of the create/destroy_irq variants from hell, i.e. 3 implementations with different semantics plus the x86 specific variants __create_irqs and create_irq_nr which have been invented in another circle of hell. x86 : x86 should be converted to irq domains and I'm deliberately making it impossible to do the multi-vector MSI support by adding more crap to the current mess. It's not that hard to do and I'm really tired of the trainwrecks which have been invented by baindaid engineering so far. Any attempt to do multi-vector MSI or ioapic hotplug without converting to irq domains is NAKed hereby. tile: Might use irq domains as well, but it has a very limited interrupt space, so handling it via this functionality might be the right thing to do even in the long run. ia64: That's an hopeless case, as I doubt that anyone has the stomach to rewrite the homebrewn dynamic allocation facilities. I stared at it for a couple of hours and gave up. The create/destroy_irq mess could be made private to itanic right away if there wouldn't be the iommu/dmar driver being shared with x86. So to do that I'm going to add a separate ia64 specific implementation later in order not to deep-six itanic right away. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: Chris Metcalf Cc: Fenghua Yu Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20140507154334.208629358@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/include/linux/irq.h b/include/linux/irq.h index 5c57efb..c75dd16 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -637,6 +637,21 @@ static inline int irq_reserve_irq(unsigned int irq) return irq_reserve_irqs(irq, 1); } +#ifdef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ +unsigned int irq_alloc_hwirqs(int cnt, int node); +static inline unsigned int irq_alloc_hwirq(int node) +{ + return irq_alloc_hwirqs(1, node); +} +void irq_free_hwirqs(unsigned int from, int cnt); +static inline void irq_free_hwirq(unsigned int irq) +{ + return irq_free_hwirqs(irq, 1); +} +int arch_setup_hwirq(unsigned int irq, int node); +void arch_teardown_hwirq(unsigned int irq); +#endif + #ifndef irq_reg_writel # define irq_reg_writel(val, addr) writel(val, addr) #endif diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index 07cbdfe..a83f10e 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig @@ -17,6 +17,11 @@ config GENERIC_IRQ_SHOW config GENERIC_IRQ_SHOW_LEVEL bool +# Facility to allocate a hardware interrupt. This is legacy support +# and should not be used in new code. Use irq domains instead. +config GENERIC_IRQ_LEGACY_ALLOC_HWIRQ + bool + # Support for delayed migration from interrupt context config GENERIC_PENDING_IRQ bool diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index bb07f29..f388ade 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -396,6 +396,57 @@ err: } EXPORT_SYMBOL_GPL(__irq_alloc_descs); +#ifdef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ +/** + * irq_alloc_hwirqs - Allocate an irq descriptor and initialize the hardware + * @cnt: number of interrupts to allocate + * @node: node on which to allocate + * + * Returns an interrupt number > 0 or 0, if the allocation fails. + */ +unsigned int irq_alloc_hwirqs(int cnt, int node) +{ + int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL); + + if (irq < 0) + return 0; + + for (i = irq; cnt > 0; i++, cnt--) { + if (arch_setup_hwirq(i, node)) + goto err; + irq_clear_status_flags(i, _IRQ_NOREQUEST); + } + return irq; + +err: + for (i--; i >= irq; i--) { + irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE); + arch_teardown_hwirq(i); + } + irq_free_descs(irq, cnt); + return 0; +} +EXPORT_SYMBOL_GPL(irq_alloc_hwirqs); + +/** + * irq_free_hwirqs - Free irq descriptor and cleanup the hardware + * @from: Free from irq number + * @cnt: number of interrupts to free + * + */ +void irq_free_hwirqs(unsigned int from, int cnt) +{ + int i; + + for (i = from; cnt > 0; i++, cnt--) { + irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE); + arch_teardown_hwirq(i); + } + irq_free_descs(from, cnt); +} +EXPORT_SYMBOL_GPL(irq_free_hwirqs); +#endif + /** * irq_reserve_irqs - mark irqs allocated * @from: mark from irq number -- cgit v0.10.2 From b1ee544174fd0eb28a7770403b9577fd70f1cd3d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:06 +0000 Subject: x86: Implement arch_setup/teardown_hwirq() This is just a cleanup to get rid of the create/destroy_irq variants which were designed in hell. The long term solution for x86 is to switch over to irq domains and cleanup the whole vector allocation mess. The generic irq_alloc_hwirqs() interface deliberately prevents multi-MSI vector allocation to further enforce the irq domain conversion (aside of the desire to support ioapic hotplug). Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20140507154334.482904047@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 25d2c6f..4724770 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -831,6 +831,7 @@ config X86_LOCAL_APIC config X86_IO_APIC def_bool y depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC || PCI_MSI + select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ config X86_REROUTE_FOR_BROKEN_BOOT_IRQS bool "Reroute for broken boot IRQs" diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 992060e..b7175c0 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -3010,6 +3010,39 @@ void destroy_irqs(unsigned int irq, unsigned int count) destroy_irq(irq + i); } +int arch_setup_hwirq(unsigned int irq, int node) +{ + struct irq_cfg *cfg; + unsigned long flags; + int ret; + + cfg = alloc_irq_cfg(irq, node); + if (!cfg) + return -ENOMEM; + + raw_spin_lock_irqsave(&vector_lock, flags); + ret = __assign_irq_vector(irq, cfg, apic->target_cpus()); + raw_spin_unlock_irqrestore(&vector_lock, flags); + + if (!ret) + irq_set_chip_data(irq, cfg); + else + free_irq_cfg(irq, cfg); + return ret; +} + +void arch_teardown_hwirq(unsigned int irq) +{ + struct irq_cfg *cfg = irq_get_chip_data(irq); + unsigned long flags; + + free_remapped_irq(irq); + raw_spin_lock_irqsave(&vector_lock, flags); + __clear_irq_vector(irq, cfg); + raw_spin_unlock_irqrestore(&vector_lock, flags); + free_irq_cfg(irq, cfg); +} + /* * MSI message composition */ -- cgit v0.10.2 From d24a135412ab4dba50eb7aeffd4064eee23b4da6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:07 +0000 Subject: x86: irq_remapping: Use irq_alloc/free_hwirq() The create_irq variants are going away. Use the new interface. The core and arch code already excludes the gsi interrupts from the allocation, so no functional change. This does not replace the requirement to move x86 to irq domains, but it limits the mess to some degree. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Acked-by: Joerg Roedel Cc: x86@kernel.org Cc: iommu@lists.linux-foundation.org Link: http://lkml.kernel.org/r/20140507154334.741805075@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 228632c9..33c4395 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -51,7 +51,7 @@ static void irq_remapping_disable_io_apic(void) static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) { - int node, ret, sub_handle, nvec_pow2, index = 0; + int ret, sub_handle, nvec_pow2, index = 0; unsigned int irq; struct msi_desc *msidesc; @@ -61,8 +61,7 @@ static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) WARN_ON(msidesc->msi_attrib.multiple); WARN_ON(msidesc->nvec_used); - node = dev_to_node(&dev->dev); - irq = __create_irqs(get_nr_irqs_gsi(), nvec, node); + irq = irq_alloc_hwirqs(nvec, dev_to_node(&dev->dev)); if (irq == 0) return -ENOSPC; @@ -89,7 +88,7 @@ static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) return 0; error: - destroy_irqs(irq, nvec); + irq_free_hwirqs(irq, nvec); /* * Restore altered MSI descriptor fields and prevent just destroyed @@ -109,12 +108,11 @@ static int do_setup_msix_irqs(struct pci_dev *dev, int nvec) unsigned int irq; node = dev_to_node(&dev->dev); - irq = get_nr_irqs_gsi(); sub_handle = 0; list_for_each_entry(msidesc, &dev->msi_list, list) { - irq = create_irq_nr(irq, node); + irq = irq_alloc_hwirq(node); if (irq == 0) return -1; @@ -137,7 +135,7 @@ static int do_setup_msix_irqs(struct pci_dev *dev, int nvec) return 0; error: - destroy_irq(irq); + irq_free_hwirq(irq); return ret; } -- cgit v0.10.2 From 499c2b75e9c695b57faaf6a63fde391ff9e523a3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:07 +0000 Subject: x86: hpet: Use irq_alloc/free_hwirq() Use the new interfaces. No functional change. This does not replace the requirement to move x86 to irq domains, but it limits the mess to some degree. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20140507154334.991589924@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 4177bfb..5f5a147 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -479,7 +479,7 @@ static int hpet_msi_next_event(unsigned long delta, static int hpet_setup_msi_irq(unsigned int irq) { if (x86_msi.setup_hpet_msi(irq, hpet_blockid)) { - destroy_irq(irq); + irq_free_hwirq(irq); return -EINVAL; } return 0; @@ -487,9 +487,8 @@ static int hpet_setup_msi_irq(unsigned int irq) static int hpet_assign_irq(struct hpet_dev *dev) { - unsigned int irq; + unsigned int irq = irq_alloc_hwirq(-1); - irq = create_irq_nr(0, -1); if (!irq) return -EINVAL; -- cgit v0.10.2 From 0a2db49dc4fe2873f857617d320c37b6bfe40255 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:08 +0000 Subject: x86: uv: Use irq_alloc/free_hwirq() No functional change. The request to allocate the irq above NR_IRQS_LEGACY is completely pointless as the implementation enforces that the dynamic allocations are above the GSI interrupts, which includes the legacy PIT irqs. This does not replace the requirement to move x86 to irq domains, but it limits the mess to some degree. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20140507154335.252789823@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/x86/platform/uv/uv_irq.c b/arch/x86/platform/uv/uv_irq.c index acf7752..b233681 100644 --- a/arch/x86/platform/uv/uv_irq.c +++ b/arch/x86/platform/uv/uv_irq.c @@ -238,11 +238,9 @@ uv_set_irq_affinity(struct irq_data *data, const struct cpumask *mask, int uv_setup_irq(char *irq_name, int cpu, int mmr_blade, unsigned long mmr_offset, int limit) { - int irq, ret; + int ret, irq = irq_alloc_hwirq(uv_blade_to_memory_nid(mmr_blade)); - irq = create_irq_nr(NR_IRQS_LEGACY, uv_blade_to_memory_nid(mmr_blade)); - - if (irq <= 0) + if (!irq) return -EBUSY; ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset, @@ -250,7 +248,7 @@ int uv_setup_irq(char *irq_name, int cpu, int mmr_blade, if (ret == irq) uv_set_irq_2_mmr_info(irq, mmr_offset, mmr_blade); else - destroy_irq(irq); + irq_free_hwirq(irq); return ret; } @@ -285,6 +283,6 @@ void uv_teardown_irq(unsigned int irq) n = n->rb_right; } spin_unlock_irqrestore(&uv_irq_lock, irqflags); - destroy_irq(irq); + irq_free_hwirq(irq); } EXPORT_SYMBOL_GPL(uv_teardown_irq); -- cgit v0.10.2 From 59b47ddc0b4d7ea8a625512e802832730c1feeb4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:08 +0000 Subject: x86: htirq: Use irq_alloc/free_irq() No functional change, just cleaned up a bit. This does not replace the requirement to move x86 to irq domains, but it limits the mess to some degree. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Acked-by: Bjorn Helgaas Cc: x86@kernel.org Cc: linux-pci@vger.kernel.org Link: http://lkml.kernel.org/r/20140507154335.452206351@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index 6e373ea..d68b030 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -87,12 +87,9 @@ void unmask_ht_irq(struct irq_data *data) int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) { struct ht_irq_cfg *cfg; + int max_irq, pos, irq; unsigned long flags; u32 data; - int max_irq; - int pos; - int irq; - int node; pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ); if (!pos) @@ -120,10 +117,8 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) cfg->msg.address_lo = 0xffffffff; cfg->msg.address_hi = 0xffffffff; - node = dev_to_node(&dev->dev); - irq = create_irq_nr(0, node); - - if (irq <= 0) { + irq = irq_alloc_hwirq(dev_to_node(&dev->dev)); + if (!irq) { kfree(cfg); return -EBUSY; } @@ -166,7 +161,7 @@ void ht_destroy_irq(unsigned int irq) cfg = irq_get_handler_data(irq); irq_set_chip(irq, NULL); irq_set_handler_data(irq, NULL); - destroy_irq(irq); + irq_free_hwirq(irq); kfree(cfg); } -- cgit v0.10.2 From be47be6c28a83dd8b3c5540d0be3675af1ac7b2e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:09 +0000 Subject: x86: ioapic: Use irq_alloc/free_hwirq() No functional change just less crap. This does not replace the requirement to move x86 to irq domains, but it limits the mess to some degree. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20140507154335.749579081@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index b7175c0..3c17b25 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -3169,8 +3169,8 @@ int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) { - unsigned int irq, irq_want; struct msi_desc *msidesc; + unsigned int irq; int node, ret; /* Multiple MSI vectors only supported with interrupt remapping */ @@ -3178,28 +3178,25 @@ int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) return 1; node = dev_to_node(&dev->dev); - irq_want = nr_irqs_gsi; + list_for_each_entry(msidesc, &dev->msi_list, list) { - irq = create_irq_nr(irq_want, node); - if (irq == 0) + irq = irq_alloc_hwirq(node); + if (!irq) return -ENOSPC; - irq_want = irq + 1; - ret = setup_msi_irq(dev, msidesc, irq, 0); - if (ret < 0) - goto error; + if (ret < 0) { + irq_free_hwirq(irq); + return ret; + } + } return 0; - -error: - destroy_irq(irq); - return ret; } void native_teardown_msi_irq(unsigned int irq) { - destroy_irq(irq); + irq_free_hwirq(irq); } #ifdef CONFIG_DMAR_TABLE -- cgit v0.10.2 From d07c9f18756e8231909a9bbcbfa7502c60cbc810 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:10 +0000 Subject: x86: Get rid of get_nr_irqs_gsi() No need to expose this outside of the ioapic code. The dynamic allocations are guaranteed not to happen in the gsi space. See commit 62a08ae2a. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: x86@kernel.org Cc: Konrad Rzeszutek Wilk Cc: xen-devel@lists.xenproject.org Link: http://lkml.kernel.org/r/20140507154335.959870037@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index 459e50a..90f97b4 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h @@ -168,8 +168,6 @@ extern int save_ioapic_entries(void); extern void mask_ioapic_entries(void); extern int restore_ioapic_entries(void); -extern int get_nr_irqs_gsi(void); - extern void setup_ioapic_ids_from_mpc(void); extern void setup_ioapic_ids_from_mpc_nocheck(void); diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 3c17b25..be3b574 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -3450,11 +3450,6 @@ static void __init probe_nr_irqs_gsi(void) printk(KERN_DEBUG "nr_irqs_gsi: %d\n", nr_irqs_gsi); } -int get_nr_irqs_gsi(void) -{ - return nr_irqs_gsi; -} - unsigned int arch_dynirq_lower_bound(unsigned int from) { return from < nr_irqs_gsi ? nr_irqs_gsi : from; diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index dfa12a4..c919d3d 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -390,22 +390,7 @@ static void xen_irq_init(unsigned irq) static int __must_check xen_allocate_irqs_dynamic(int nvec) { - int first = 0; - int i, irq; - -#ifdef CONFIG_X86_IO_APIC - /* - * For an HVM guest or domain 0 which see "real" (emulated or - * actual respectively) GSIs we allocate dynamic IRQs - * e.g. those corresponding to event channels or MSIs - * etc. from the range above those "real" GSIs to avoid - * collisions. - */ - if (xen_initial_domain() || xen_hvm_domain()) - first = get_nr_irqs_gsi(); -#endif - - irq = irq_alloc_descs_from(first, nvec, -1); + int i, irq = irq_alloc_descs(-1, 0, nvec, -1); if (irq >= 0) { for (i = 0; i < nvec; i++) -- cgit v0.10.2 From aa5125a45568f8f666f6d2f224fe8ab261b1069e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:10 +0000 Subject: iommu: smar: Fix return value check of create_irq() ia64 returns a negative error code when allocation fails andx86 returns 0. Make it handle both. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: Fenghua Yu Cc: x86@kernel.org Acked-by: Joerg Roedel Cc: linux-ia64@vger.kernel.org Cc: iommu@lists.linux-foundation.org Link: http://lkml.kernel.org/r/20140507154336.178850165@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 39f8b71..3ce1f62 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -1551,7 +1551,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu) return 0; irq = create_irq(); - if (!irq) { + if (irq <= 0) { pr_err("IOMMU: no free vectors\n"); return -EINVAL; } -- cgit v0.10.2 From a553b142b8effbfcbba24ebbf8c07a1a86d32ce6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:11 +0000 Subject: iommu: dmar: Provide arch specific irq allocation ia64 and x86 share this driver. x86 is moving to a different irq allocation and ia64 keeps its private irq_create/destroy stuff. Use macros to redirect to one or the other. Yes, macros to avoid include hell. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: Fenghua Yu Acked-by: Joerg Roedel Cc: x86@kernel.org Cc: linux-ia64@vger.kernel.org Cc: iommu@lists.linux-foundation.org Link: http://lkml.kernel.org/r/20140507154336.372289825@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/ia64/include/asm/irq_remapping.h b/arch/ia64/include/asm/irq_remapping.h index a8687b1..e3b3556 100644 --- a/arch/ia64/include/asm/irq_remapping.h +++ b/arch/ia64/include/asm/irq_remapping.h @@ -1,4 +1,6 @@ #ifndef __IA64_INTR_REMAPPING_H #define __IA64_INTR_REMAPPING_H #define irq_remapping_enabled 0 +#define dmar_alloc_hwirq create_irq +#define dmar_free_hwirq destroy_irq #endif diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h index d806b22..b7747c4 100644 --- a/arch/x86/include/asm/irq_remapping.h +++ b/arch/x86/include/asm/irq_remapping.h @@ -103,4 +103,7 @@ static inline bool setup_remapped_irq(int irq, } #endif /* CONFIG_IRQ_REMAP */ +#define dmar_alloc_hwirq() irq_alloc_hwirq(-1) +#define dmar_free_hwirq irq_free_hwirq + #endif /* __X86_IRQ_REMAPPING_H */ diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 3ce1f62..9a4f05e 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -994,7 +994,7 @@ static void free_iommu(struct intel_iommu *iommu) if (iommu->irq) { free_irq(iommu->irq, iommu); irq_set_handler_data(iommu->irq, NULL); - destroy_irq(iommu->irq); + dmar_free_hwirq(iommu->irq); } if (iommu->qi) { @@ -1550,7 +1550,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu) if (iommu->irq) return 0; - irq = create_irq(); + irq = dmar_alloc_hwirq(); if (irq <= 0) { pr_err("IOMMU: no free vectors\n"); return -EINVAL; @@ -1563,7 +1563,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu) if (ret) { irq_set_handler_data(irq, NULL); iommu->irq = 0; - destroy_irq(irq); + dmar_free_hwirq(irq); return ret; } -- cgit v0.10.2 From fd5d8abf8bdf9519f40058b5cd24b6ab37b214b4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:11 +0000 Subject: ia64: Remove unused check_irq_used() Just stumbled over it when staring into ia64 irq handling. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Tested-by: Tony Luck Cc: Peter Zijlstra Cc: Fenghua Yu Link: http://lkml.kernel.org/r/20140507154336.566531793@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/ia64/include/asm/hw_irq.h b/arch/ia64/include/asm/hw_irq.h index a681d02..029bab3 100644 --- a/arch/ia64/include/asm/hw_irq.h +++ b/arch/ia64/include/asm/hw_irq.h @@ -132,7 +132,6 @@ extern int reserve_irq_vector (int vector); extern void __setup_vector_irq(int cpu); extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); extern void ia64_native_register_percpu_irq (ia64_vector vec, struct irqaction *action); -extern int check_irq_used (int irq); extern void destroy_and_reserve_irq (unsigned int irq); #if defined(CONFIG_SMP) && (defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_DIG)) diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 0884f5e..5774c3b 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -93,14 +93,6 @@ static int irq_status[NR_IRQS] = { [0 ... NR_IRQS -1] = IRQ_UNUSED }; -int check_irq_used(int irq) -{ - if (irq_status[irq] == IRQ_USED) - return 1; - - return -1; -} - static inline int find_unassigned_irq(void) { int irq; -- cgit v0.10.2 From 54859f59fc18e5c104a4095420b3fcef8bc3ae63 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:12 +0000 Subject: x86: Remove create/destroy_irq() No more users. Remove the cruft Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20140507154336.760446122@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index be3b574..efda2f6 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -281,18 +281,6 @@ static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node) return cfg; } -static int alloc_irqs_from(unsigned int from, unsigned int count, int node) -{ - return irq_alloc_descs_from(from, count, node); -} - -static void free_irq_at(unsigned int at, struct irq_cfg *cfg) -{ - free_irq_cfg(at, cfg); - irq_free_desc(at); -} - - struct io_apic { unsigned int index; unsigned int unused[3]; @@ -2916,100 +2904,8 @@ static int __init ioapic_init_ops(void) device_initcall(ioapic_init_ops); /* - * Dynamic irq allocate and deallocation + * Dynamic irq allocate and deallocation. Should be replaced by irq domains! */ -unsigned int __create_irqs(unsigned int from, unsigned int count, int node) -{ - struct irq_cfg **cfg; - unsigned long flags; - int irq, i; - - if (from < nr_irqs_gsi) - from = nr_irqs_gsi; - - cfg = kzalloc_node(count * sizeof(cfg[0]), GFP_KERNEL, node); - if (!cfg) - return 0; - - irq = alloc_irqs_from(from, count, node); - if (irq < 0) - goto out_cfgs; - - for (i = 0; i < count; i++) { - cfg[i] = alloc_irq_cfg(irq + i, node); - if (!cfg[i]) - goto out_irqs; - } - - raw_spin_lock_irqsave(&vector_lock, flags); - for (i = 0; i < count; i++) - if (__assign_irq_vector(irq + i, cfg[i], apic->target_cpus())) - goto out_vecs; - raw_spin_unlock_irqrestore(&vector_lock, flags); - - for (i = 0; i < count; i++) { - irq_set_chip_data(irq + i, cfg[i]); - irq_clear_status_flags(irq + i, IRQ_NOREQUEST); - } - - kfree(cfg); - return irq; - -out_vecs: - for (i--; i >= 0; i--) - __clear_irq_vector(irq + i, cfg[i]); - raw_spin_unlock_irqrestore(&vector_lock, flags); -out_irqs: - for (i = 0; i < count; i++) - free_irq_at(irq + i, cfg[i]); -out_cfgs: - kfree(cfg); - return 0; -} - -unsigned int create_irq_nr(unsigned int from, int node) -{ - return __create_irqs(from, 1, node); -} - -int create_irq(void) -{ - int node = cpu_to_node(0); - unsigned int irq_want; - int irq; - - irq_want = nr_irqs_gsi; - irq = create_irq_nr(irq_want, node); - - if (irq == 0) - irq = -1; - - return irq; -} - -void destroy_irq(unsigned int irq) -{ - struct irq_cfg *cfg = irq_get_chip_data(irq); - unsigned long flags; - - irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE); - - free_remapped_irq(irq); - - raw_spin_lock_irqsave(&vector_lock, flags); - __clear_irq_vector(irq, cfg); - raw_spin_unlock_irqrestore(&vector_lock, flags); - free_irq_at(irq, cfg); -} - -void destroy_irqs(unsigned int irq, unsigned int count) -{ - unsigned int i; - - for (i = 0; i < count; i++) - destroy_irq(irq + i); -} - int arch_setup_hwirq(unsigned int irq, int node) { struct irq_cfg *cfg; diff --git a/include/linux/irq.h b/include/linux/irq.h index c75dd16..7549ed5 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -526,12 +526,8 @@ static inline void irq_set_percpu_devid_flags(unsigned int irq) } /* Handle dynamic irq creation and destruction */ -extern unsigned int create_irq_nr(unsigned int irq_want, int node); -extern unsigned int __create_irqs(unsigned int from, unsigned int count, - int node); extern int create_irq(void); extern void destroy_irq(unsigned int irq); -extern void destroy_irqs(unsigned int irq, unsigned int count); /* * Dynamic irq helper functions. Obsolete. Use irq_alloc_desc* and -- cgit v0.10.2 From 6ef40512c55b18f8fdf1074b2f2d7eadcd50fec7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:13 +0000 Subject: tile: Implement irq_alloc/free_hwirq() for migration We want to convert the drivers over to the new interface and finally tile to sparse irqs. Implement irq_alloc/free_hwirq() for step by step migration. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Acked-by: Chris Metcalf Link: http://lkml.kernel.org/r/20140507154336.947853241@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/tile/include/asm/irq.h b/arch/tile/include/asm/irq.h index 33cff9a..9670a39 100644 --- a/arch/tile/include/asm/irq.h +++ b/arch/tile/include/asm/irq.h @@ -76,4 +76,7 @@ void tile_irq_activate(unsigned int irq, int tile_irq_type); void setup_irq_regs(void); +unsigned int irq_alloc_hwirq(int node); +void irq_free_hwirq(unsigned int irq); + #endif /* _ASM_TILE_IRQ_H */ diff --git a/arch/tile/kernel/irq.c b/arch/tile/kernel/irq.c index 906a76b..5fd197e 100644 --- a/arch/tile/kernel/irq.c +++ b/arch/tile/kernel/irq.c @@ -312,4 +312,16 @@ void destroy_irq(unsigned int irq) spin_unlock_irqrestore(&available_irqs_lock, flags); } EXPORT_SYMBOL(destroy_irq); + +unsigned int irq_alloc_hwirq(int node) +{ + int ret = create_irq(); + return ret < 0 ? 0 : ret; +} + +void irq_free_hwirq(unsigned int irq) +{ + destroy_irq(irq); +} + #endif -- cgit v0.10.2 From 7e5f01b1a1504b2777342628e365c1a0c6600b0e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:13 +0000 Subject: tile: usb: Use irq_alloc/free_hwirq No functional change. Just convert to the new interface. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Acked-by: Chris Metcalf Link: http://lkml.kernel.org/r/20140507154337.177939962@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/drivers/usb/host/ehci-tilegx.c b/drivers/usb/host/ehci-tilegx.c index f3713d3..0d24767 100644 --- a/drivers/usb/host/ehci-tilegx.c +++ b/drivers/usb/host/ehci-tilegx.c @@ -142,8 +142,8 @@ static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev) ehci->hcs_params = readl(&ehci->caps->hcs_params); /* Create our IRQs and register them. */ - pdata->irq = create_irq(); - if (pdata->irq < 0) { + pdata->irq = irq_alloc_hwirq(-1); + if (!pdata->irq) { ret = -ENXIO; goto err_no_irq; } @@ -175,7 +175,7 @@ static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev) } err_have_irq: - destroy_irq(pdata->irq); + irq_free_hwirq(pdata->irq); err_no_irq: tilegx_stop_ehc(); usb_put_hcd(hcd); @@ -193,7 +193,7 @@ static int ehci_hcd_tilegx_drv_remove(struct platform_device *pdev) usb_put_hcd(hcd); tilegx_stop_ehc(); gxio_usb_host_destroy(&pdata->usb_ctx); - destroy_irq(pdata->irq); + irq_free_hwirq(pdata->irq); return 0; } diff --git a/drivers/usb/host/ohci-tilegx.c b/drivers/usb/host/ohci-tilegx.c index 0b183e0..bef6dfb 100644 --- a/drivers/usb/host/ohci-tilegx.c +++ b/drivers/usb/host/ohci-tilegx.c @@ -129,8 +129,8 @@ static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev) tilegx_start_ohc(); /* Create our IRQs and register them. */ - pdata->irq = create_irq(); - if (pdata->irq < 0) { + pdata->irq = irq_alloc_hwirq(-1); + if (!pdata->irq) { ret = -ENXIO; goto err_no_irq; } @@ -164,7 +164,7 @@ static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev) } err_have_irq: - destroy_irq(pdata->irq); + irq_free_hwirq(pdata->irq); err_no_irq: tilegx_stop_ohc(); usb_put_hcd(hcd); @@ -182,7 +182,7 @@ static int ohci_hcd_tilegx_drv_remove(struct platform_device *pdev) usb_put_hcd(hcd); tilegx_stop_ohc(); gxio_usb_host_destroy(&pdata->usb_ctx); - destroy_irq(pdata->irq); + irq_free_hwirq(pdata->irq); return 0; } -- cgit v0.10.2 From 094e873c2a0bd54ced4e98f1f6f612b1fc60f426 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:14 +0000 Subject: tile: net: Use irq_alloc/free_hwirq No functional change. Just convert to the new interface. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Acked-by: Chris Metcalf Link: http://lkml.kernel.org/r/20140507154337.410843062@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 7e1c91d..449011b 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -1208,8 +1208,8 @@ static int tile_net_setup_interrupts(struct net_device *dev) irq = md->ingress_irq; if (irq < 0) { - irq = create_irq(); - if (irq < 0) { + irq = irq_alloc_hwirq(-1); + if (!irq) { netdev_err(dev, "create_irq failed: mpipe[%d] %d\n", instance, irq); @@ -1223,7 +1223,7 @@ static int tile_net_setup_interrupts(struct net_device *dev) if (rc != 0) { netdev_err(dev, "request_irq failed: mpipe[%d] %d\n", instance, rc); - destroy_irq(irq); + irq_free_hwirq(irq); return rc; } md->ingress_irq = irq; -- cgit v0.10.2 From 651fb13943304be2008b43adf813fa62435423d7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:15 +0000 Subject: tile: serial: Use irq_alloc/free_hwirq No functional change. Just convert to the new interface. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Acked-by: Chris Metcalf Link: http://lkml.kernel.org/r/20140507154337.643399187@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/drivers/tty/serial/tilegx.c b/drivers/tty/serial/tilegx.c index f92d7e6..613ccf0 100644 --- a/drivers/tty/serial/tilegx.c +++ b/drivers/tty/serial/tilegx.c @@ -359,8 +359,8 @@ static int tilegx_startup(struct uart_port *port) } /* Create our IRQs. */ - port->irq = create_irq(); - if (port->irq < 0) + port->irq = irq_alloc_hwirq(-1); + if (!port->irq) goto err_uart_dest; tile_irq_activate(port->irq, TILE_IRQ_PERCPU); @@ -395,7 +395,7 @@ static int tilegx_startup(struct uart_port *port) err_free_irq: free_irq(port->irq, port); err_dest_irq: - destroy_irq(port->irq); + irq_free_hwirq(port->irq); err_uart_dest: gxio_uart_destroy(context); ret = -ENXIO; @@ -435,7 +435,7 @@ static void tilegx_shutdown(struct uart_port *port) if (port->irq > 0) { free_irq(port->irq, port); - destroy_irq(port->irq); + irq_free_hwirq(port->irq); port->irq = 0; } -- cgit v0.10.2 From 3dfd442e5ffc6c488e34b6f1028bbb0ce310e6c4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:15 +0000 Subject: tile: hvc: Use irq_alloc/free_hwirq No functional change. Just convert to the new interface. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Acked-by: Chris Metcalf Link: http://lkml.kernel.org/r/20140507154337.873477334@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/drivers/tty/hvc/hvc_tile.c b/drivers/tty/hvc/hvc_tile.c index af8cdaa..147d49e 100644 --- a/drivers/tty/hvc/hvc_tile.c +++ b/drivers/tty/hvc/hvc_tile.c @@ -133,14 +133,14 @@ static int hvc_tile_probe(struct platform_device *pdev) int tile_hvc_irq; /* Create our IRQ and register it. */ - tile_hvc_irq = create_irq(); - if (tile_hvc_irq < 0) + tile_hvc_irq = irq_alloc_hwirq(-1); + if (!tile_hvc_irq) return -ENXIO; tile_irq_activate(tile_hvc_irq, TILE_IRQ_PERCPU); hp = hvc_alloc(0, tile_hvc_irq, &hvc_tile_get_put_ops, 128); if (IS_ERR(hp)) { - destroy_irq(tile_hvc_irq); + irq_free_hwirq(tile_hvc_irq); return PTR_ERR(hp); } dev_set_drvdata(&pdev->dev, hp); @@ -155,7 +155,7 @@ static int hvc_tile_remove(struct platform_device *pdev) rc = hvc_remove(hp); if (rc == 0) - destroy_irq(hp->data); + irq_free_hwirq(hp->data); return rc; } -- cgit v0.10.2 From 2aa799d891299457e4107d33f07a1ed5ac8849ae Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:16 +0000 Subject: tile: pci: Use irq_alloc/free_hwirq() No functional change. Just convert to the new interface. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Acked-by: Chris Metcalf Link: http://lkml.kernel.org/r/20140507154338.132662495@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c index 077b7bc..e39f9c5 100644 --- a/arch/tile/kernel/pci_gx.c +++ b/arch/tile/kernel/pci_gx.c @@ -350,10 +350,9 @@ static int tile_init_irqs(struct pci_controller *controller) int cpu; /* Ask the kernel to allocate an IRQ. */ - irq = create_irq(); - if (irq < 0) { + irq = irq_alloc_hwirq(-1); + if (!irq) { pr_err("PCI: no free irq vectors, failed for %d\n", i); - goto free_irqs; } controller->irq_intx_table[i] = irq; @@ -382,7 +381,7 @@ static int tile_init_irqs(struct pci_controller *controller) free_irqs: for (j = 0; j < i; j++) - destroy_irq(controller->irq_intx_table[j]); + irq_free_hwirq(controller->irq_intx_table[j]); return -1; } @@ -1500,9 +1499,9 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) int irq; int ret; - irq = create_irq(); - if (irq < 0) - return irq; + irq = irq_alloc_hwirq(-1); + if (!irq) + return -ENOSPC; /* * Since we use a 64-bit Mem-Map to accept the MSI write, we fail @@ -1601,11 +1600,11 @@ hv_msi_config_failure: /* Free mem-map */ msi_mem_map_alloc_failure: is_64_failure: - destroy_irq(irq); + irq_free_hwirq(irq); return ret; } void arch_teardown_msi_irq(unsigned int irq) { - destroy_irq(irq); + irq_free_hwirq(irq); } -- cgit v0.10.2 From b26d851ff1928b56242c4c5e16cb62bac2d9526c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:16 +0000 Subject: tile: Use SPARSE_IRQ Get rid of the private allocator and switch over to sparse IRQs. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Acked-by: Chris Metcalf Link: http://lkml.kernel.org/r/20140507154338.423715783@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 85258ca..4f3006b 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig @@ -125,6 +125,8 @@ config HVC_TILE config TILEGX bool "Building for TILE-Gx (64-bit) processor" + select SPARSE_IRQ + select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_FUNCTION_GRAPH_TRACER diff --git a/arch/tile/include/asm/irq.h b/arch/tile/include/asm/irq.h index 9670a39..1fe8691 100644 --- a/arch/tile/include/asm/irq.h +++ b/arch/tile/include/asm/irq.h @@ -18,10 +18,12 @@ #include /* The hypervisor interface provides 32 IRQs. */ -#define NR_IRQS 32 +#define NR_IRQS 32 /* IRQ numbers used for linux IPIs. */ -#define IRQ_RESCHEDULE 0 +#define IRQ_RESCHEDULE 0 +/* Interrupts for dynamic allocation start at 1. Let the core allocate irq0 */ +#define NR_IRQS_LEGACY 1 #define irq_canonicalize(irq) (irq) @@ -76,7 +78,4 @@ void tile_irq_activate(unsigned int irq, int tile_irq_type); void setup_irq_regs(void); -unsigned int irq_alloc_hwirq(int node); -void irq_free_hwirq(unsigned int irq); - #endif /* _ASM_TILE_IRQ_H */ diff --git a/arch/tile/kernel/irq.c b/arch/tile/kernel/irq.c index 5fd197e..637f2ff 100644 --- a/arch/tile/kernel/irq.c +++ b/arch/tile/kernel/irq.c @@ -54,13 +54,6 @@ static DEFINE_PER_CPU(unsigned long, irq_disable_mask) */ static DEFINE_PER_CPU(int, irq_depth); -/* State for allocating IRQs on Gx. */ -#if CHIP_HAS_IPI() -static unsigned long available_irqs = ((1UL << NR_IRQS) - 1) & - (~(1UL << IRQ_RESCHEDULE)); -static DEFINE_SPINLOCK(available_irqs_lock); -#endif - #if CHIP_HAS_IPI() /* Use SPRs to manipulate device interrupts. */ #define mask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_SET_K, irq_mask) @@ -278,50 +271,11 @@ int arch_show_interrupts(struct seq_file *p, int prec) return 0; } -/* - * Generic, controller-independent functions: - */ - #if CHIP_HAS_IPI() -int create_irq(void) -{ - unsigned long flags; - int result; - - spin_lock_irqsave(&available_irqs_lock, flags); - if (available_irqs == 0) - result = -ENOMEM; - else { - result = __ffs(available_irqs); - available_irqs &= ~(1UL << result); - dynamic_irq_init(result); - } - spin_unlock_irqrestore(&available_irqs_lock, flags); - - return result; -} -EXPORT_SYMBOL(create_irq); - -void destroy_irq(unsigned int irq) -{ - unsigned long flags; - - spin_lock_irqsave(&available_irqs_lock, flags); - available_irqs |= (1UL << irq); - dynamic_irq_cleanup(irq); - spin_unlock_irqrestore(&available_irqs_lock, flags); -} -EXPORT_SYMBOL(destroy_irq); - -unsigned int irq_alloc_hwirq(int node) -{ - int ret = create_irq(); - return ret < 0 ? 0 : ret; -} - -void irq_free_hwirq(unsigned int irq) +int arch_setup_hwirq(unsigned int irq, int node) { - destroy_irq(irq); + return irq >= NR_IRQS ? -EINVAL : 0; } +void arch_teardown_hwirq(unsigned int irq) { } #endif -- cgit v0.10.2 From e8784e4f9a578344023ae4e08a509b7c5eab5eb0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:17 +0000 Subject: genirq: Make create/destroy_irq() ia64 private No more users outside of itanic. Confine it. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Tested-by: Tony Luck Cc: Peter Zijlstra Cc: Fenghua Yu Link: http://lkml.kernel.org/r/20140507154338.700598389@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/ia64/include/asm/irq.h b/arch/ia64/include/asm/irq.h index 91b920fd..820667c 100644 --- a/arch/ia64/include/asm/irq.h +++ b/arch/ia64/include/asm/irq.h @@ -31,4 +31,7 @@ bool is_affinity_mask_valid(const struct cpumask *cpumask); #define is_affinity_mask_valid is_affinity_mask_valid +int create_irq(void); +void destroy_irq(unsigned int irq); + #endif /* _ASM_IA64_IRQ_H */ diff --git a/include/linux/irq.h b/include/linux/irq.h index 7549ed5..ac96342 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -525,10 +525,6 @@ static inline void irq_set_percpu_devid_flags(unsigned int irq) IRQ_NOPROBE | IRQ_PER_CPU_DEVID); } -/* Handle dynamic irq creation and destruction */ -extern int create_irq(void); -extern void destroy_irq(unsigned int irq); - /* * Dynamic irq helper functions. Obsolete. Use irq_alloc_desc* and * irq_free_desc instead. -- cgit v0.10.2 From 18a67d32c31b88679467e93e1825010d245b9bf4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:18 +0000 Subject: x86, irq: Remove pointless irq_reserve_irqs() call That's a leftover from the time where x86 supported SPARSE_IRQ=n. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20140507154338.967285614@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index efda2f6..9d0a979 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -206,9 +206,6 @@ int __init arch_early_irq_init(void) count = ARRAY_SIZE(irq_cfgx); node = cpu_to_node(0); - /* Make sure the legacy interrupts are marked in the bitmap */ - irq_reserve_irqs(0, legacy_pic->nr_legacy_irqs); - for (i = 0; i < count; i++) { irq_set_chip_data(i, &cfg[i]); zalloc_cpumask_var_node(&cfg[i].domain, GFP_KERNEL, node); -- cgit v0.10.2 From 3670802223e164f1089287d1c223d34d3c5dc3da Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:18 +0000 Subject: sh: intc: Remove pointless irq_reserve_irqs() invocation The preceding call to irq_create_identity_mapping() marks the interrupt as allocated already. Remove the leftover. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Acked-by: Simon Horman Cc: linux-sh@vger.kernel.org Link: http://lkml.kernel.org/r/20140507154339.189047829@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 8f32a13..81f2298 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -80,12 +80,6 @@ static void __init intc_register_irq(struct intc_desc *desc, unsigned int data[2], primary; unsigned long flags; - /* - * Register the IRQ position with the global IRQ map, then insert - * it in to the radix tree. - */ - irq_reserve_irq(irq); - raw_spin_lock_irqsave(&intc_big_lock, flags); radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq)); raw_spin_unlock_irqrestore(&intc_big_lock, flags); -- cgit v0.10.2 From 0a0a94219074d79370b1cd1b533ead63d51c3730 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:19 +0000 Subject: s390: pci: Check return value of alloc_irq_desc() proper alloc_irq_desc() returns an integer and as documented either a valid irq number or a negative error code. Checking for NO_IRQ is definitely not the proper error handling. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Link: http://lkml.kernel.org/r/20140507154339.409085048@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 1df1d29..2c0076d4 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -401,11 +401,11 @@ static void zpci_irq_handler(struct airq_struct *airq) int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) { struct zpci_dev *zdev = get_zdev(pdev); - unsigned int hwirq, irq, msi_vecs; + unsigned int hwirq, msi_vecs; unsigned long aisb; struct msi_desc *msi; struct msi_msg msg; - int rc; + int rc, irq; if (type == PCI_CAP_ID_MSI && nvec > 1) return 1; @@ -433,7 +433,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) list_for_each_entry(msi, &pdev->msi_list, list) { rc = -EIO; irq = irq_alloc_desc(0); /* Alloc irq on node 0 */ - if (irq == NO_IRQ) + if (irq < 0) goto out_msi; rc = irq_set_msi_desc(irq, msi); if (rc) -- cgit v0.10.2 From 5fdaf1bf8a60f73a11cb4431fd06daa2b295a327 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:19 +0000 Subject: s390: Remove pointless arch_show_interrupts() S390 is not using the generic show interrupts implementation so the extra arch_show_interrupts() is just useless. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Link: http://lkml.kernel.org/r/20140507154339.609149081@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index c7463aa..2fb0998 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -151,11 +151,6 @@ out: return 0; } -int arch_show_interrupts(struct seq_file *p, int prec) -{ - return 0; -} - /* * Switch to the asynchronous interrupt stack for softirq execution. */ -- cgit v0.10.2 From be4034016c11f8913d38fccf692007fab1c50be1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:20 +0000 Subject: s390: Avoid call to irq_reserve_irqs() There is no need to mark the lower interrupts as reserved in order to exclude them from dynamic allocation. Provide arch_dynirq_lower_bound() to exclude the lower space. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Cc: Tony Luck Cc: Peter Zijlstra Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Link: http://lkml.kernel.org/r/20140507154339.811205235@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 2fb0998..99b0b09 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -92,7 +92,6 @@ static const struct irq_class irqclass_sub_desc[NR_ARCH_IRQS] = { void __init init_IRQ(void) { - irq_reserve_irqs(0, THIN_INTERRUPT); init_cio_interrupts(); init_airq_interrupts(); init_ext_interrupts(); @@ -151,6 +150,11 @@ out: return 0; } +unsigned int arch_dynirq_lower_bound(unsigned int from) +{ + return from < THIN_INTERRUPT ? THIN_INTERRUPT : from; +} + /* * Switch to the asynchronous interrupt stack for softirq execution. */ -- cgit v0.10.2 From f63b6a05f2b11537612266a8b27a61f412344a1d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:21 +0000 Subject: genirq: Replace reserve_irqs in core code We want to get rid of the public interface. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Tested-by: Tony Luck Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140507154340.061990194@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 6397df2..a2b28a2 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -40,10 +40,9 @@ int irq_set_chip(unsigned int irq, struct irq_chip *chip) irq_put_desc_unlock(desc, flags); /* * For !CONFIG_SPARSE_IRQ make the irq show up in - * allocated_irqs. For the CONFIG_SPARSE_IRQ case, it is - * already marked, and this call is harmless. + * allocated_irqs. */ - irq_reserve_irq(irq); + irq_mark_irq(irq); return 0; } EXPORT_SYMBOL(irq_set_chip); diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index ddf1ffe..c4065e3 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -76,6 +76,12 @@ extern void mask_irq(struct irq_desc *desc); extern void unmask_irq(struct irq_desc *desc); extern void unmask_threaded_irq(struct irq_desc *desc); +#ifdef CONFIG_SPARSE_IRQ +static inline void irq_mark_irq(unsigned int irq) { } +#else +extern void irq_mark_irq(unsigned int irq); +#endif + extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); irqreturn_t handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action); diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index f388ade..2402934 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -299,6 +299,13 @@ static int irq_expand_nr_irqs(unsigned int nr) return -ENOMEM; } +void irq_mark_irq(unsigned int irq) +{ + mutex_lock(&sparse_irq_lock); + bitmap_set(allocated_irqs, irq, 1); + mutex_unlock(&sparse_irq_lock); +} + #endif /* !CONFIG_SPARSE_IRQ */ /** -- cgit v0.10.2 From 1d008353ba088fdec0b2a944e140ff9154a5fb20 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:21 +0000 Subject: genirq: Remove irq_reserve_irq[s] No more users. And it's not going to come back. If you need hotplugable irq chips, use irq domains. Signed-off-by: Thomas Gleixner Reviewed-and-acked-by: Grant Likely Tested-by: Tony Luck Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140507154340.302183048@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/include/linux/irq.h b/include/linux/irq.h index ac96342..2110f46 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -617,18 +617,11 @@ int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, irq_alloc_descs(-1, from, cnt, node) void irq_free_descs(unsigned int irq, unsigned int cnt); -int irq_reserve_irqs(unsigned int from, unsigned int cnt); - static inline void irq_free_desc(unsigned int irq) { irq_free_descs(irq, 1); } -static inline int irq_reserve_irq(unsigned int irq) -{ - return irq_reserve_irqs(irq, 1); -} - #ifdef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ unsigned int irq_alloc_hwirqs(int cnt, int node); static inline unsigned int irq_alloc_hwirq(int node) diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 2402934..d514ed6 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -455,31 +455,6 @@ EXPORT_SYMBOL_GPL(irq_free_hwirqs); #endif /** - * irq_reserve_irqs - mark irqs allocated - * @from: mark from irq number - * @cnt: number of irqs to mark - * - * Returns 0 on success or an appropriate error code - */ -int irq_reserve_irqs(unsigned int from, unsigned int cnt) -{ - unsigned int start; - int ret = 0; - - if (!cnt || (from + cnt) > nr_irqs) - return -EINVAL; - - mutex_lock(&sparse_irq_lock); - start = bitmap_find_next_zero_area(allocated_irqs, nr_irqs, from, cnt, 0); - if (start == from) - bitmap_set(allocated_irqs, start, cnt); - else - ret = -EEXIST; - mutex_unlock(&sparse_irq_lock); - return ret; -} - -/** * irq_get_next_irq - get next allocated irq number * @offset: where to start the search * -- cgit v0.10.2 From c940e01c94e73a2a5318f1b82038e0746aaec753 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:22 +0000 Subject: genirq: Replace dynamic_irq_init/cleanup Create a new interface and confine it with a config switch which makes clear that this is just legacy support and not to be used for new code. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Tested-by: Tony Luck Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140507154340.574437049@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/include/linux/irq.h b/include/linux/irq.h index 2110f46..8ff71d1 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -637,6 +637,10 @@ int arch_setup_hwirq(unsigned int irq, int node); void arch_teardown_hwirq(unsigned int irq); #endif +#ifdef CONFIG_GENERIC_IRQ_LEGACY +void irq_init_desc(unsigned int irq); +#endif + #ifndef irq_reg_writel # define irq_reg_writel(val, addr) writel(val, addr) #endif diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index a83f10e..d269cec 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig @@ -5,6 +5,10 @@ menu "IRQ subsystem" config MAY_HAVE_SPARSE_IRQ bool +# Legacy support, required for itanic +config GENERIC_IRQ_LEGACY + bool + # Enable the generic irq autoprobe mechanism config GENERIC_IRQ_PROBE bool diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index d514ed6..7f26779 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -306,6 +306,13 @@ void irq_mark_irq(unsigned int irq) mutex_unlock(&sparse_irq_lock); } +#ifdef CONFIG_GENERIC_IRQ_LEGACY +void irq_init_desc(unsigned int irq) +{ + dynamic_irq_cleanup(irq); +} +#endif + #endif /* !CONFIG_SPARSE_IRQ */ /** -- cgit v0.10.2 From 4debd723f4934910ad1df279d80da16827f9b583 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:22 +0000 Subject: ia64: Use irq_init_desc Switch over to the new interface. No functional change. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Tested-by: Tony Luck Cc: Peter Zijlstra Cc: Fenghua Yu Link: http://lkml.kernel.org/r/20140507154340.782586778@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 12c3afe..2f3abcf 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -32,6 +32,7 @@ config IA64 select GENERIC_IRQ_PROBE select GENERIC_PENDING_IRQ if SMP select GENERIC_IRQ_SHOW + select GENERIC_IRQ_LEGACY select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_HAVE_NMI_SAFE_CMPXCHG select GENERIC_IOMAP diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 19f107b..cd44a57 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -735,7 +735,7 @@ iosapic_register_intr (unsigned int gsi, rte = find_rte(irq, gsi); if(iosapic_intr_info[irq].count == 0) { assign_irq_vector(irq); - dynamic_irq_init(irq); + irq_init_desc(irq); } else if (rte->refcnt != NO_REF_RTE) { rte->refcnt++; goto unlock_iosapic_lock; diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 5774c3b..03ea78e 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -382,8 +382,7 @@ void destroy_and_reserve_irq(unsigned int irq) { unsigned long flags; - dynamic_irq_cleanup(irq); - + irq_init_desc(irq); spin_lock_irqsave(&vector_lock, flags); __clear_irq_vector(irq); irq_status[irq] = IRQ_RSVD; @@ -416,13 +415,13 @@ int create_irq(void) out: spin_unlock_irqrestore(&vector_lock, flags); if (irq >= 0) - dynamic_irq_init(irq); + irq_init_desc(irq); return irq; } void destroy_irq(unsigned int irq) { - dynamic_irq_cleanup(irq); + irq_init_desc(irq); clear_irq_vector(irq); } -- cgit v0.10.2 From d8179bc0db8d0c9654d5de43de2874bf6d0a58fa Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 May 2014 15:44:23 +0000 Subject: genirq: Remove dynamic_irq mess No more users. Get rid of the cruft. Signed-off-by: Thomas Gleixner Reviewed-by: Grant Likely Tested-by: Tony Luck Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140507154341.012847637@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/include/linux/irq.h b/include/linux/irq.h index 8ff71d1..0d998d8 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -525,16 +525,6 @@ static inline void irq_set_percpu_devid_flags(unsigned int irq) IRQ_NOPROBE | IRQ_PER_CPU_DEVID); } -/* - * Dynamic irq helper functions. Obsolete. Use irq_alloc_desc* and - * irq_free_desc instead. - */ -extern void dynamic_irq_cleanup(unsigned int irq); -static inline void dynamic_irq_init(unsigned int irq) -{ - dynamic_irq_cleanup(irq); -} - /* Set/get chip/data for an IRQ: */ extern int irq_set_chip(unsigned int irq, struct irq_chip *chip); extern int irq_set_handler_data(unsigned int irq, void *data); diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 7f26779..7339e42 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -278,7 +278,12 @@ EXPORT_SYMBOL(irq_to_desc); static void free_desc(unsigned int irq) { - dynamic_irq_cleanup(irq); + struct irq_desc *desc = irq_to_desc(irq); + unsigned long flags; + + raw_spin_lock_irqsave(&desc->lock, flags); + desc_set_defaults(irq, desc, desc_node(desc), NULL); + raw_spin_unlock_irqrestore(&desc->lock, flags); } static inline int alloc_descs(unsigned int start, unsigned int cnt, int node, @@ -309,7 +314,7 @@ void irq_mark_irq(unsigned int irq) #ifdef CONFIG_GENERIC_IRQ_LEGACY void irq_init_desc(unsigned int irq) { - dynamic_irq_cleanup(irq); + free_desc(irq); } #endif @@ -522,20 +527,6 @@ int irq_set_percpu_devid(unsigned int irq) return 0; } -/** - * dynamic_irq_cleanup - cleanup a dynamically allocated irq - * @irq: irq number to initialize - */ -void dynamic_irq_cleanup(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - unsigned long flags; - - raw_spin_lock_irqsave(&desc->lock, flags); - desc_set_defaults(irq, desc, desc_node(desc), NULL); - raw_spin_unlock_irqrestore(&desc->lock, flags); -} - void kstat_incr_irq_this_cpu(unsigned int irq) { kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq)); -- cgit v0.10.2 From b8802f76fe473d91886220498aeda157c492f2d1 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Sun, 11 May 2014 16:05:58 +0800 Subject: irqchip: gic: Use mask field in GICC_IAR Bit[9:0] is interrupt ID field in GICC_IAR. Bit[12:10] is CPU ID field, and others are reserved. So we should use GICC_IAR_INT_ID_MASK to get interrupt ID. It's not a good way to use ~0x1c00 (CPU ID field) to get interrupt ID. Signed-off-by: Haojian Zhuang Link: https://lkml.kernel.org/r/1399795571-17231-3-git-send-email-haojian.zhuang@linaro.org Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4300b66..f711fb6 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -287,7 +287,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) do { irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); - irqnr = irqstat & ~0x1c00; + irqnr = irqstat & GICC_IAR_INT_ID_MASK; if (likely(irqnr > 15 && irqnr < 1021)) { irqnr = irq_find_mapping(gic->domain, irqnr); diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 7ed92d0..45e2d8c 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -21,6 +21,8 @@ #define GIC_CPU_ACTIVEPRIO 0xd0 #define GIC_CPU_IDENT 0xfc +#define GICC_IAR_INT_ID_MASK 0x3ff + #define GIC_DIST_CTRL 0x000 #define GIC_DIST_CTR 0x004 #define GIC_DIST_IGROUP 0x080 -- cgit v0.10.2 From d8f17c49d3f26b5700624819adfd5349798b5162 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Sun, 18 May 2014 21:02:17 -0300 Subject: irqchip: armada-370-xp: Move the devicetree binding documentation Move the devicetree binding documentation to the interrupt-controller directory, where it belongs. Reviewed-by: Thomas Petazzoni Signed-off-by: Ezequiel Garcia Link: https://lkml.kernel.org/r/1400457737-1617-1-git-send-email-ezequiel.garcia@free-electrons.com Signed-off-by: Jason Cooper diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt b/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt deleted file mode 100644 index 5fc0313..0000000 --- a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt +++ /dev/null @@ -1,38 +0,0 @@ -Marvell Armada 370, 375, 38x, XP Interrupt Controller ------------------------------------------------------ - -Required properties: -- compatible: Should be "marvell,mpic" -- interrupt-controller: Identifies the node as an interrupt controller. -- msi-controller: Identifies the node as an PCI Message Signaled - Interrupt controller. -- #interrupt-cells: The number of cells to define the interrupts. Should be 1. - The cell is the IRQ number - -- reg: Should contain PMIC registers location and length. First pair - for the main interrupt registers, second pair for the per-CPU - interrupt registers. For this last pair, to be compliant with SMP - support, the "virtual" must be use (For the record, these registers - automatically map to the interrupt controller registers of the - current CPU) - -Optional properties: - -- interrupts: If defined, then it indicates that this MPIC is - connected as a slave to another interrupt controller. This is - typically the case on Armada 375 and Armada 38x, where the MPIC is - connected as a slave to the Cortex-A9 GIC. The provided interrupt - indicate to which GIC interrupt the MPIC output is connected. - -Example: - - mpic: interrupt-controller@d0020000 { - compatible = "marvell,mpic"; - #interrupt-cells = <1>; - #address-cells = <1>; - #size-cells = <1>; - interrupt-controller; - msi-controller; - reg = <0xd0020a00 0x1d0>, - <0xd0021070 0x58>; - }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,armada-370-xp-mpic.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,armada-370-xp-mpic.txt new file mode 100644 index 0000000..5fc0313 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,armada-370-xp-mpic.txt @@ -0,0 +1,38 @@ +Marvell Armada 370, 375, 38x, XP Interrupt Controller +----------------------------------------------------- + +Required properties: +- compatible: Should be "marvell,mpic" +- interrupt-controller: Identifies the node as an interrupt controller. +- msi-controller: Identifies the node as an PCI Message Signaled + Interrupt controller. +- #interrupt-cells: The number of cells to define the interrupts. Should be 1. + The cell is the IRQ number + +- reg: Should contain PMIC registers location and length. First pair + for the main interrupt registers, second pair for the per-CPU + interrupt registers. For this last pair, to be compliant with SMP + support, the "virtual" must be use (For the record, these registers + automatically map to the interrupt controller registers of the + current CPU) + +Optional properties: + +- interrupts: If defined, then it indicates that this MPIC is + connected as a slave to another interrupt controller. This is + typically the case on Armada 375 and Armada 38x, where the MPIC is + connected as a slave to the Cortex-A9 GIC. The provided interrupt + indicate to which GIC interrupt the MPIC output is connected. + +Example: + + mpic: interrupt-controller@d0020000 { + compatible = "marvell,mpic"; + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-controller; + msi-controller; + reg = <0xd0020a00 0x1d0>, + <0xd0021070 0x58>; + }; -- cgit v0.10.2 From f0ba3d05c9c647ab42ed6a0dbdfdeae42bfbd6de Mon Sep 17 00:00:00 2001 From: Eyal Perry Date: Tue, 20 May 2014 17:57:00 +0300 Subject: genirq: Provide !SMP stub for irq_set_affinity_notifier() Instead of requiring each consumer of the IRQ affinity notifier to have themselves be explicitly dependent on CONFIG_SMP, make the definition of struct irq_affinity_notify to exist independently of that config option and introduce a stub for irq_set_affinity_notifier() under non SMP configuration. Fixes: 2eacc23 ("net/mlx4_core: Enforce irq affinity changes immediatly") Signed-off-by: Eyal Perry Signed-off-by: Amir Vadai Cc: Ben Hutchings Cc: Yevgeny Petrilin Cc: Or Gerlitz Cc: David S. Miller Link: http://lkml.kernel.org/r/1400597820-30685-1-git-send-email-amirv@mellanox.com Signed-off-by: Thomas Gleixner diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 97ac926..3f74c059 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -199,6 +199,26 @@ extern int check_wakeup_irqs(void); static inline int check_wakeup_irqs(void) { return 0; } #endif +/** + * struct irq_affinity_notify - context for notification of IRQ affinity changes + * @irq: Interrupt to which notification applies + * @kref: Reference count, for internal use + * @work: Work item, for internal use + * @notify: Function to be called on change. This will be + * called in process context. + * @release: Function to be called on release. This will be + * called in process context. Once registered, the + * structure must only be freed when this function is + * called or later. + */ +struct irq_affinity_notify { + unsigned int irq; + struct kref kref; + struct work_struct work; + void (*notify)(struct irq_affinity_notify *, const cpumask_t *mask); + void (*release)(struct kref *ref); +}; + #if defined(CONFIG_SMP) extern cpumask_var_t irq_default_affinity; @@ -242,26 +262,6 @@ extern int irq_select_affinity(unsigned int irq); extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m); -/** - * struct irq_affinity_notify - context for notification of IRQ affinity changes - * @irq: Interrupt to which notification applies - * @kref: Reference count, for internal use - * @work: Work item, for internal use - * @notify: Function to be called on change. This will be - * called in process context. - * @release: Function to be called on release. This will be - * called in process context. Once registered, the - * structure must only be freed when this function is - * called or later. - */ -struct irq_affinity_notify { - unsigned int irq; - struct kref kref; - struct work_struct work; - void (*notify)(struct irq_affinity_notify *, const cpumask_t *mask); - void (*release)(struct kref *ref); -}; - extern int irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); @@ -284,6 +284,12 @@ static inline int irq_set_affinity_hint(unsigned int irq, { return -EINVAL; } + +static inline int +irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify) +{ + return 0; +} #endif /* CONFIG_SMP */ /* -- cgit v0.10.2 From 8d2af85e87eda746ff50801f5decd8aed9aed28e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 26 May 2014 17:12:10 +0200 Subject: ARM: iop13xx: fix msi support with sparse IRQ patch 37ebbcff7837 ("arm: iop13xx: Use sparse irqs for MSI") moved iop13xx over to sparse IRQ support, but this broke the build for the msi.c file, which now has to include mach/irqs.h itself. Signed-off-by: Arnd Bergmann Cc: Grant Likely Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/12285212.fBJyVfk69p@wuerfel Signed-off-by: Thomas Gleixner diff --git a/arch/arm/mach-iop13xx/msi.c b/arch/arm/mach-iop13xx/msi.c index 655072d..e7730cf 100644 --- a/arch/arm/mach-iop13xx/msi.c +++ b/arch/arm/mach-iop13xx/msi.c @@ -23,6 +23,7 @@ #include #include #include +#include /* IMIPR0 CP6 R8 Page 1 */ -- cgit v0.10.2 From a257954bb38ab23dbf93df812b4b2c01cae29d8b Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 27 May 2014 16:07:37 +0800 Subject: genirq: Improve documentation to match current implementation Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Jiri Kosina Link: http://lkml.kernel.org/r/1401178092-1228-3-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt index 03df71a..8a8b82c 100644 --- a/Documentation/IRQ-domain.txt +++ b/Documentation/IRQ-domain.txt @@ -41,8 +41,7 @@ An interrupt controller driver creates and registers an irq_domain by calling one of the irq_domain_add_*() functions (each mapping method has a different allocator function, more on that later). The function will return a pointer to the irq_domain on success. The caller must -provide the allocator function with an irq_domain_ops structure with -the .map callback populated as a minimum. +provide the allocator function with an irq_domain_ops structure. In most cases, the irq_domain will begin empty without any mappings between hwirq and IRQ numbers. Mappings are added to the irq_domain diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index c4065e3..099ea2e 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -33,7 +33,7 @@ enum { }; /* - * Bit masks for desc->state + * Bit masks for desc->core_internal_state__do_not_mess_with_it * * IRQS_AUTODETECT - autodetection in progress * IRQS_SPURIOUS_DISABLED - was disabled due to spurious interrupt diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index f140337..eb5e10e 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -27,14 +27,14 @@ static struct irq_domain *irq_default_domain; * __irq_domain_add() - Allocate a new irq_domain data structure * @of_node: optional device-tree node of the interrupt controller * @size: Size of linear map; 0 for radix mapping only + * @hwirq_max: Maximum number of interrupts supported by controller * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no * direct mapping * @ops: map/unmap domain callbacks * @host_data: Controller private data pointer * - * Allocates and initialize and irq_domain structure. Caller is expected to - * register allocated irq_domain with irq_domain_register(). Returns pointer - * to IRQ domain, or NULL on failure. + * Allocates and initialize and irq_domain structure. + * Returns pointer to IRQ domain, or NULL on failure. */ struct irq_domain *__irq_domain_add(struct device_node *of_node, int size, irq_hw_number_t hwirq_max, int direct_max, -- cgit v0.10.2 From 7f646e92766e2070f31dbe542a80b4383918d81d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 23 May 2014 17:40:53 -0700 Subject: irqchip: brcmstb-l2: Add Broadcom Set Top Box Level-2 interrupt controller This patch adds support for the Level-2 interrupt controller hardware found in Broadcom Set Top Box System-on-a-Chip devices. This interrupt controller is implemented using the generic IRQ chip driver with separate enable and disable registers. Signed-off-by: Brian Norris Link: https://lkml.kernel.org/r/1400892054-24457-2-git-send-email-f.fainelli@gmail.com Signed-off-by: Florian Fainelli Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index d770f74..bbb746e 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -30,6 +30,12 @@ config ARM_VIC_NR The maximum number of VICs available in the system, for power management. +config BRCMSTB_L2_IRQ + bool + depends on ARM + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + config DW_APB_ICTL bool select IRQ_DOMAIN diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index f180f8d..62a13e5 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o +obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c new file mode 100644 index 0000000..8ee2a36 --- /dev/null +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -0,0 +1,202 @@ +/* + * Generic Broadcom Set Top Box Level 2 Interrupt controller driver + * + * Copyright (C) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "irqchip.h" + +/* Register offsets in the L2 interrupt controller */ +#define CPU_STATUS 0x00 +#define CPU_SET 0x04 +#define CPU_CLEAR 0x08 +#define CPU_MASK_STATUS 0x0c +#define CPU_MASK_SET 0x10 +#define CPU_MASK_CLEAR 0x14 + +/* L2 intc private data structure */ +struct brcmstb_l2_intc_data { + int parent_irq; + void __iomem *base; + struct irq_domain *domain; + bool can_wake; + u32 saved_mask; /* for suspend/resume */ +}; + +static void brcmstb_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) +{ + struct brcmstb_l2_intc_data *b = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + u32 status; + + chained_irq_enter(chip, desc); + + status = __raw_readl(b->base + CPU_STATUS) & + ~(__raw_readl(b->base + CPU_MASK_STATUS)); + + if (status == 0) { + do_bad_IRQ(irq, desc); + goto out; + } + + do { + irq = ffs(status) - 1; + /* ack at our level */ + __raw_writel(1 << irq, b->base + CPU_CLEAR); + status &= ~(1 << irq); + generic_handle_irq(irq_find_mapping(b->domain, irq)); + } while (status); +out: + chained_irq_exit(chip, desc); +} + +static void brcmstb_l2_intc_suspend(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct brcmstb_l2_intc_data *b = gc->private; + + irq_gc_lock(gc); + /* Save the current mask */ + b->saved_mask = __raw_readl(b->base + CPU_MASK_STATUS); + + if (b->can_wake) { + /* Program the wakeup mask */ + __raw_writel(~gc->wake_active, b->base + CPU_MASK_SET); + __raw_writel(gc->wake_active, b->base + CPU_MASK_CLEAR); + } + irq_gc_unlock(gc); +} + +static void brcmstb_l2_intc_resume(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct brcmstb_l2_intc_data *b = gc->private; + + irq_gc_lock(gc); + /* Clear unmasked non-wakeup interrupts */ + __raw_writel(~b->saved_mask & ~gc->wake_active, b->base + CPU_CLEAR); + + /* Restore the saved mask */ + __raw_writel(b->saved_mask, b->base + CPU_MASK_SET); + __raw_writel(~b->saved_mask, b->base + CPU_MASK_CLEAR); + irq_gc_unlock(gc); +} + +int __init brcmstb_l2_intc_of_init(struct device_node *np, + struct device_node *parent) +{ + unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; + struct brcmstb_l2_intc_data *data; + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + int ret; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->base = of_iomap(np, 0); + if (!data->base) { + pr_err("failed to remap intc L2 registers\n"); + ret = -ENOMEM; + goto out_free; + } + + /* Disable all interrupts by default */ + __raw_writel(0xffffffff, data->base + CPU_MASK_SET); + __raw_writel(0xffffffff, data->base + CPU_CLEAR); + + data->parent_irq = irq_of_parse_and_map(np, 0); + if (data->parent_irq < 0) { + pr_err("failed to find parent interrupt\n"); + ret = data->parent_irq; + goto out_unmap; + } + + data->domain = irq_domain_add_linear(np, 32, + &irq_generic_chip_ops, NULL); + if (!data->domain) { + ret = -ENOMEM; + goto out_unmap; + } + + /* Allocate a single Generic IRQ chip for this node */ + ret = irq_alloc_domain_generic_chips(data->domain, 32, 1, + np->full_name, handle_level_irq, clr, 0, 0); + if (ret) { + pr_err("failed to allocate generic irq chip\n"); + goto out_free_domain; + } + + /* Set the IRQ chaining logic */ + irq_set_handler_data(data->parent_irq, data); + irq_set_chained_handler(data->parent_irq, brcmstb_l2_intc_irq_handle); + + gc = irq_get_domain_generic_chip(data->domain, 0); + gc->reg_base = data->base; + gc->private = data; + ct = gc->chip_types; + + ct->chip.irq_ack = irq_gc_ack_set_bit; + ct->regs.ack = CPU_CLEAR; + + ct->chip.irq_mask = irq_gc_mask_disable_reg; + ct->regs.disable = CPU_MASK_SET; + + ct->chip.irq_unmask = irq_gc_unmask_enable_reg; + ct->regs.enable = CPU_MASK_CLEAR; + + ct->chip.irq_suspend = brcmstb_l2_intc_suspend; + ct->chip.irq_resume = brcmstb_l2_intc_resume; + + if (of_property_read_bool(np, "brcm,irq-can-wake")) { + data->can_wake = true; + /* This IRQ chip can wake the system, set all child interrupts + * in wake_enabled mask + */ + gc->wake_enabled = 0xffffffff; + ct->chip.irq_set_wake = irq_gc_set_wake; + } + + pr_info("registered L2 intc (mem: 0x%p, parent irq: %d)\n", + data->base, data->parent_irq); + + return 0; + +out_free_domain: + irq_domain_remove(data->domain); +out_unmap: + iounmap(data->base); +out_free: + kfree(data); + return ret; +} +IRQCHIP_DECLARE(brcmstb_l2_intc, "brcm,l2-intc", brcmstb_l2_intc_of_init); -- cgit v0.10.2 From c8dfe94bc7a14c6a644ce55ef77b7a81505c696f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 23 May 2014 17:40:54 -0700 Subject: Documentation: brcmstb-l2: Add Broadcom STB Level-2 interrupt controller binding This patch adds the Device Tree binding document for the Broadcom Set-top-box Level 2 interrupt controller hardware. Signed-off-by: Brian Norris Link: https://lkml.kernel.org/r/1400892054-24457-3-git-send-email-f.fainelli@gmail.com Signed-off-by: Florian Fainelli Signed-off-by: Jason Cooper diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,l2-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,l2-intc.txt new file mode 100644 index 0000000..448273a --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,l2-intc.txt @@ -0,0 +1,29 @@ +Broadcom Generic Level 2 Interrupt Controller + +Required properties: + +- compatible: should be "brcm,l2-intc" +- reg: specifies the base physical address and size of the registers +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an + interrupt source. Should be 1. +- interrupt-parent: specifies the phandle to the parent interrupt controller + this controller is cacaded from +- interrupts: specifies the interrupt line in the interrupt-parent irq space + to be used for cascading + +Optional properties: + +- brcm,irq-can-wake: If present, this means the L2 controller can be used as a + wakeup source for system suspend/resume. + +Example: + +hif_intr2_intc: interrupt-controller@f0441000 { + compatible = "brcm,l2-intc"; + reg = <0xf0441000 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&intc>; + interrupts = <0x0 0x20 0x0>; +}; -- cgit v0.10.2