diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-04 18:59:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-04 18:59:13 -0400 |
commit | d09cc3659db494aca4b3bb2393c533fb4946b794 (patch) | |
tree | 158d1dd5fa5fddf1c99da677a193b8561c11274d | |
parent | 82e627eb5e07d7993216c9e63fb5550cf6ed25d7 (diff) | |
parent | c0ffa793994a7a69c37a96dabf38323eae1dffa6 (diff) |
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into next
Pull core irq updates from Thomas Gleixner:
"The irq department delivers:
- Another tree wide update to get rid of the horrible create_irq
interface along with its even more horrible variants. That also
gets rid of the last leftovers of the initial sparse irq hackery.
arch/driver specific changes have been either acked or ignored.
- A fix for the spurious interrupt detection logic with threaded
interrupts.
- A new ARM SoC interrupt controller
- The usual pile of fixes and improvements all over the place"
* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (40 commits)
Documentation: brcmstb-l2: Add Broadcom STB Level-2 interrupt controller binding
irqchip: brcmstb-l2: Add Broadcom Set Top Box Level-2 interrupt controller
genirq: Improve documentation to match current implementation
ARM: iop13xx: fix msi support with sparse IRQ
genirq: Provide !SMP stub for irq_set_affinity_notifier()
irqchip: armada-370-xp: Move the devicetree binding documentation
irqchip: gic: Use mask field in GICC_IAR
genirq: Remove dynamic_irq mess
ia64: Use irq_init_desc
genirq: Replace dynamic_irq_init/cleanup
genirq: Remove irq_reserve_irq[s]
genirq: Replace reserve_irqs in core code
s390: Avoid call to irq_reserve_irqs()
s390: Remove pointless arch_show_interrupts()
s390: pci: Check return value of alloc_irq_desc() proper
sh: intc: Remove pointless irq_reserve_irqs() invocation
x86, irq: Remove pointless irq_reserve_irqs() call
genirq: Make create/destroy_irq() ia64 private
tile: Use SPARSE_IRQ
tile: pci: Use irq_alloc/free_hwirq()
...
56 files changed, 597 insertions, 396 deletions
diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt index 03df71aeb38c..8a8b82c9ca53 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 | |||
41 | calling one of the irq_domain_add_*() functions (each mapping method | 41 | calling one of the irq_domain_add_*() functions (each mapping method |
42 | has a different allocator function, more on that later). The function | 42 | has a different allocator function, more on that later). The function |
43 | will return a pointer to the irq_domain on success. The caller must | 43 | will return a pointer to the irq_domain on success. The caller must |
44 | provide the allocator function with an irq_domain_ops structure with | 44 | provide the allocator function with an irq_domain_ops structure. |
45 | the .map callback populated as a minimum. | ||
46 | 45 | ||
47 | In most cases, the irq_domain will begin empty without any mappings | 46 | In most cases, the irq_domain will begin empty without any mappings |
48 | between hwirq and IRQ numbers. Mappings are added to the irq_domain | 47 | between hwirq and IRQ numbers. Mappings are added to the irq_domain |
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 000000000000..448273a30a11 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,l2-intc.txt | |||
@@ -0,0 +1,29 @@ | |||
1 | Broadcom Generic Level 2 Interrupt Controller | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible: should be "brcm,l2-intc" | ||
6 | - reg: specifies the base physical address and size of the registers | ||
7 | - interrupt-controller: identifies the node as an interrupt controller | ||
8 | - #interrupt-cells: specifies the number of cells needed to encode an | ||
9 | interrupt source. Should be 1. | ||
10 | - interrupt-parent: specifies the phandle to the parent interrupt controller | ||
11 | this controller is cacaded from | ||
12 | - interrupts: specifies the interrupt line in the interrupt-parent irq space | ||
13 | to be used for cascading | ||
14 | |||
15 | Optional properties: | ||
16 | |||
17 | - brcm,irq-can-wake: If present, this means the L2 controller can be used as a | ||
18 | wakeup source for system suspend/resume. | ||
19 | |||
20 | Example: | ||
21 | |||
22 | hif_intr2_intc: interrupt-controller@f0441000 { | ||
23 | compatible = "brcm,l2-intc"; | ||
24 | reg = <0xf0441000 0x30>; | ||
25 | interrupt-controller; | ||
26 | #interrupt-cells = <1>; | ||
27 | interrupt-parent = <&intc>; | ||
28 | interrupts = <0x0 0x20 0x0>; | ||
29 | }; | ||
diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,armada-370-xp-mpic.txt index 5fc03134a999..5fc03134a999 100644 --- a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,armada-370-xp-mpic.txt | |||
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 071dce78959a..ad89a033f17f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -480,6 +480,7 @@ config ARCH_IOP13XX | |||
480 | select PCI | 480 | select PCI |
481 | select PLAT_IOP | 481 | select PLAT_IOP |
482 | select VMSPLIT_1G | 482 | select VMSPLIT_1G |
483 | select SPARSE_IRQ | ||
483 | help | 484 | help |
484 | Support for Intel's IOP13XX (XScale) family of processors. | 485 | Support for Intel's IOP13XX (XScale) family of processors. |
485 | 486 | ||
diff --git a/arch/arm/mach-iop13xx/include/mach/irqs.h b/arch/arm/mach-iop13xx/include/mach/irqs.h index 054e7acb5bfa..e8d24d32121a 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) | |||
191 | #define NR_IOP13XX_IRQS (IRQ_IOP13XX_HPI + 1) | 191 | #define NR_IOP13XX_IRQS (IRQ_IOP13XX_HPI + 1) |
192 | #endif | 192 | #endif |
193 | 193 | ||
194 | #define NR_IRQS NR_IOP13XX_IRQS | ||
195 | |||
196 | #endif /* _IOP13XX_IRQ_H_ */ | 194 | #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 f1c00d6d560b..15bc9bb78a6b 100644 --- a/arch/arm/mach-iop13xx/include/mach/time.h +++ b/arch/arm/mach-iop13xx/include/mach/time.h | |||
@@ -1,5 +1,8 @@ | |||
1 | #ifndef _IOP13XX_TIME_H_ | 1 | #ifndef _IOP13XX_TIME_H_ |
2 | #define _IOP13XX_TIME_H_ | 2 | #define _IOP13XX_TIME_H_ |
3 | |||
4 | #include <mach/irqs.h> | ||
5 | |||
3 | #define IRQ_IOP_TIMER0 IRQ_IOP13XX_TIMER0 | 6 | #define IRQ_IOP_TIMER0 IRQ_IOP13XX_TIMER0 |
4 | 7 | ||
5 | #define IOP_TMR_EN 0x02 | 8 | #define IOP_TMR_EN 0x02 |
diff --git a/arch/arm/mach-iop13xx/iq81340mc.c b/arch/arm/mach-iop13xx/iq81340mc.c index 02a8228ac2d3..9cd07d396093 100644 --- a/arch/arm/mach-iop13xx/iq81340mc.c +++ b/arch/arm/mach-iop13xx/iq81340mc.c | |||
@@ -93,4 +93,5 @@ MACHINE_START(IQ81340MC, "Intel IQ81340MC") | |||
93 | .init_time = iq81340mc_timer_init, | 93 | .init_time = iq81340mc_timer_init, |
94 | .init_machine = iq81340mc_init, | 94 | .init_machine = iq81340mc_init, |
95 | .restart = iop13xx_restart, | 95 | .restart = iop13xx_restart, |
96 | .nr_irqs = NR_IOP13XX_IRQS, | ||
96 | MACHINE_END | 97 | MACHINE_END |
diff --git a/arch/arm/mach-iop13xx/iq81340sc.c b/arch/arm/mach-iop13xx/iq81340sc.c index 1b80f10722b3..b3ec11cb707e 100644 --- a/arch/arm/mach-iop13xx/iq81340sc.c +++ b/arch/arm/mach-iop13xx/iq81340sc.c | |||
@@ -95,4 +95,5 @@ MACHINE_START(IQ81340SC, "Intel IQ81340SC") | |||
95 | .init_time = iq81340sc_timer_init, | 95 | .init_time = iq81340sc_timer_init, |
96 | .init_machine = iq81340sc_init, | 96 | .init_machine = iq81340sc_init, |
97 | .restart = iop13xx_restart, | 97 | .restart = iop13xx_restart, |
98 | .nr_irqs = NR_IOP13XX_IRQS, | ||
98 | MACHINE_END | 99 | MACHINE_END |
diff --git a/arch/arm/mach-iop13xx/msi.c b/arch/arm/mach-iop13xx/msi.c index 560d5b2dec22..e7730cf9c15d 100644 --- a/arch/arm/mach-iop13xx/msi.c +++ b/arch/arm/mach-iop13xx/msi.c | |||
@@ -23,10 +23,7 @@ | |||
23 | #include <linux/msi.h> | 23 | #include <linux/msi.h> |
24 | #include <asm/mach/irq.h> | 24 | #include <asm/mach/irq.h> |
25 | #include <asm/irq.h> | 25 | #include <asm/irq.h> |
26 | 26 | #include <mach/irqs.h> | |
27 | |||
28 | #define IOP13XX_NUM_MSI_IRQS 128 | ||
29 | static DECLARE_BITMAP(msi_irq_in_use, IOP13XX_NUM_MSI_IRQS); | ||
30 | 27 | ||
31 | /* IMIPR0 CP6 R8 Page 1 | 28 | /* IMIPR0 CP6 R8 Page 1 |
32 | */ | 29 | */ |
@@ -121,41 +118,6 @@ void __init iop13xx_msi_init(void) | |||
121 | irq_set_chained_handler(IRQ_IOP13XX_INBD_MSI, iop13xx_msi_handler); | 118 | irq_set_chained_handler(IRQ_IOP13XX_INBD_MSI, iop13xx_msi_handler); |
122 | } | 119 | } |
123 | 120 | ||
124 | /* | ||
125 | * Dynamic irq allocate and deallocation | ||
126 | */ | ||
127 | int create_irq(void) | ||
128 | { | ||
129 | int irq, pos; | ||
130 | |||
131 | again: | ||
132 | pos = find_first_zero_bit(msi_irq_in_use, IOP13XX_NUM_MSI_IRQS); | ||
133 | irq = IRQ_IOP13XX_MSI_0 + pos; | ||
134 | if (irq > NR_IRQS) | ||
135 | return -ENOSPC; | ||
136 | /* test_and_set_bit operates on 32-bits at a time */ | ||
137 | if (test_and_set_bit(pos, msi_irq_in_use)) | ||
138 | goto again; | ||
139 | |||
140 | dynamic_irq_init(irq); | ||
141 | |||
142 | return irq; | ||
143 | } | ||
144 | |||
145 | void destroy_irq(unsigned int irq) | ||
146 | { | ||
147 | int pos = irq - IRQ_IOP13XX_MSI_0; | ||
148 | |||
149 | dynamic_irq_cleanup(irq); | ||
150 | |||
151 | clear_bit(pos, msi_irq_in_use); | ||
152 | } | ||
153 | |||
154 | void arch_teardown_msi_irq(unsigned int irq) | ||
155 | { | ||
156 | destroy_irq(irq); | ||
157 | } | ||
158 | |||
159 | static void iop13xx_msi_nop(struct irq_data *d) | 121 | static void iop13xx_msi_nop(struct irq_data *d) |
160 | { | 122 | { |
161 | return; | 123 | return; |
@@ -172,12 +134,17 @@ static struct irq_chip iop13xx_msi_chip = { | |||
172 | 134 | ||
173 | int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) | 135 | int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) |
174 | { | 136 | { |
175 | int id, irq = create_irq(); | 137 | int id, irq = irq_alloc_desc_from(IRQ_IOP13XX_MSI_0, -1); |
176 | struct msi_msg msg; | 138 | struct msi_msg msg; |
177 | 139 | ||
178 | if (irq < 0) | 140 | if (irq < 0) |
179 | return irq; | 141 | return irq; |
180 | 142 | ||
143 | if (irq >= NR_IOP13XX_IRQS) { | ||
144 | irq_free_desc(irq); | ||
145 | return -ENOSPC; | ||
146 | } | ||
147 | |||
181 | irq_set_msi_desc(irq, desc); | 148 | irq_set_msi_desc(irq, desc); |
182 | 149 | ||
183 | msg.address_hi = 0x0; | 150 | msg.address_hi = 0x0; |
@@ -191,3 +158,8 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) | |||
191 | 158 | ||
192 | return 0; | 159 | return 0; |
193 | } | 160 | } |
161 | |||
162 | void arch_teardown_msi_irq(unsigned int irq) | ||
163 | { | ||
164 | irq_free_desc(irq); | ||
165 | } | ||
diff --git a/arch/arm/mach-iop13xx/setup.c b/arch/arm/mach-iop13xx/setup.c index 96e6c7a6793b..bca96f433495 100644 --- a/arch/arm/mach-iop13xx/setup.c +++ b/arch/arm/mach-iop13xx/setup.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <mach/hardware.h> | 27 | #include <mach/hardware.h> |
28 | #include <asm/irq.h> | 28 | #include <asm/irq.h> |
29 | #include <asm/hardware/iop_adma.h> | 29 | #include <asm/hardware/iop_adma.h> |
30 | #include <mach/irqs.h> | ||
30 | 31 | ||
31 | #define IOP13XX_UART_XTAL 33334000 | 32 | #define IOP13XX_UART_XTAL 33334000 |
32 | #define IOP13XX_SETUP_DEBUG 0 | 33 | #define IOP13XX_SETUP_DEBUG 0 |
diff --git a/arch/arm/mach-iop13xx/tpmi.c b/arch/arm/mach-iop13xx/tpmi.c index 6fdad7a0425a..db511ec2b1df 100644 --- a/arch/arm/mach-iop13xx/tpmi.c +++ b/arch/arm/mach-iop13xx/tpmi.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/io.h> | 24 | #include <linux/io.h> |
25 | #include <asm/irq.h> | 25 | #include <asm/irq.h> |
26 | #include <asm/sizes.h> | 26 | #include <asm/sizes.h> |
27 | #include <mach/irqs.h> | ||
27 | 28 | ||
28 | /* assumes CONTROLLER_ONLY# is never asserted in the ESSR register */ | 29 | /* assumes CONTROLLER_ONLY# is never asserted in the ESSR register */ |
29 | #define IOP13XX_TPMI_MMR(dev) IOP13XX_REG_ADDR32_PHYS(0x48000 + (dev << 12)) | 30 | #define IOP13XX_TPMI_MMR(dev) IOP13XX_REG_ADDR32_PHYS(0x48000 + (dev << 12)) |
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 12c3afee0f6f..2f3abcf8f6bc 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig | |||
@@ -32,6 +32,7 @@ config IA64 | |||
32 | select GENERIC_IRQ_PROBE | 32 | select GENERIC_IRQ_PROBE |
33 | select GENERIC_PENDING_IRQ if SMP | 33 | select GENERIC_PENDING_IRQ if SMP |
34 | select GENERIC_IRQ_SHOW | 34 | select GENERIC_IRQ_SHOW |
35 | select GENERIC_IRQ_LEGACY | ||
35 | select ARCH_WANT_OPTIONAL_GPIOLIB | 36 | select ARCH_WANT_OPTIONAL_GPIOLIB |
36 | select ARCH_HAVE_NMI_SAFE_CMPXCHG | 37 | select ARCH_HAVE_NMI_SAFE_CMPXCHG |
37 | select GENERIC_IOMAP | 38 | select GENERIC_IOMAP |
diff --git a/arch/ia64/include/asm/hw_irq.h b/arch/ia64/include/asm/hw_irq.h index a681d02cb324..029bab36cd91 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); | |||
132 | extern void __setup_vector_irq(int cpu); | 132 | extern void __setup_vector_irq(int cpu); |
133 | extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); | 133 | extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); |
134 | extern void ia64_native_register_percpu_irq (ia64_vector vec, struct irqaction *action); | 134 | extern void ia64_native_register_percpu_irq (ia64_vector vec, struct irqaction *action); |
135 | extern int check_irq_used (int irq); | ||
136 | extern void destroy_and_reserve_irq (unsigned int irq); | 135 | extern void destroy_and_reserve_irq (unsigned int irq); |
137 | 136 | ||
138 | #if defined(CONFIG_SMP) && (defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_DIG)) | 137 | #if defined(CONFIG_SMP) && (defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_DIG)) |
diff --git a/arch/ia64/include/asm/irq.h b/arch/ia64/include/asm/irq.h index 91b920fd7d53..820667cbea7e 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); | |||
31 | 31 | ||
32 | #define is_affinity_mask_valid is_affinity_mask_valid | 32 | #define is_affinity_mask_valid is_affinity_mask_valid |
33 | 33 | ||
34 | int create_irq(void); | ||
35 | void destroy_irq(unsigned int irq); | ||
36 | |||
34 | #endif /* _ASM_IA64_IRQ_H */ | 37 | #endif /* _ASM_IA64_IRQ_H */ |
diff --git a/arch/ia64/include/asm/irq_remapping.h b/arch/ia64/include/asm/irq_remapping.h index a8687b1d8906..e3b3556e2e1b 100644 --- a/arch/ia64/include/asm/irq_remapping.h +++ b/arch/ia64/include/asm/irq_remapping.h | |||
@@ -1,4 +1,6 @@ | |||
1 | #ifndef __IA64_INTR_REMAPPING_H | 1 | #ifndef __IA64_INTR_REMAPPING_H |
2 | #define __IA64_INTR_REMAPPING_H | 2 | #define __IA64_INTR_REMAPPING_H |
3 | #define irq_remapping_enabled 0 | 3 | #define irq_remapping_enabled 0 |
4 | #define dmar_alloc_hwirq create_irq | ||
5 | #define dmar_free_hwirq destroy_irq | ||
4 | #endif | 6 | #endif |
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 19f107be734e..cd44a57c73be 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c | |||
@@ -735,7 +735,7 @@ iosapic_register_intr (unsigned int gsi, | |||
735 | rte = find_rte(irq, gsi); | 735 | rte = find_rte(irq, gsi); |
736 | if(iosapic_intr_info[irq].count == 0) { | 736 | if(iosapic_intr_info[irq].count == 0) { |
737 | assign_irq_vector(irq); | 737 | assign_irq_vector(irq); |
738 | dynamic_irq_init(irq); | 738 | irq_init_desc(irq); |
739 | } else if (rte->refcnt != NO_REF_RTE) { | 739 | } else if (rte->refcnt != NO_REF_RTE) { |
740 | rte->refcnt++; | 740 | rte->refcnt++; |
741 | goto unlock_iosapic_lock; | 741 | goto unlock_iosapic_lock; |
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 0884f5ecbcc3..03ea78ed64a9 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] = { | |||
93 | [0 ... NR_IRQS -1] = IRQ_UNUSED | 93 | [0 ... NR_IRQS -1] = IRQ_UNUSED |
94 | }; | 94 | }; |
95 | 95 | ||
96 | int check_irq_used(int irq) | ||
97 | { | ||
98 | if (irq_status[irq] == IRQ_USED) | ||
99 | return 1; | ||
100 | |||
101 | return -1; | ||
102 | } | ||
103 | |||
104 | static inline int find_unassigned_irq(void) | 96 | static inline int find_unassigned_irq(void) |
105 | { | 97 | { |
106 | int irq; | 98 | int irq; |
@@ -390,8 +382,7 @@ void destroy_and_reserve_irq(unsigned int irq) | |||
390 | { | 382 | { |
391 | unsigned long flags; | 383 | unsigned long flags; |
392 | 384 | ||
393 | dynamic_irq_cleanup(irq); | 385 | irq_init_desc(irq); |
394 | |||
395 | spin_lock_irqsave(&vector_lock, flags); | 386 | spin_lock_irqsave(&vector_lock, flags); |
396 | __clear_irq_vector(irq); | 387 | __clear_irq_vector(irq); |
397 | irq_status[irq] = IRQ_RSVD; | 388 | irq_status[irq] = IRQ_RSVD; |
@@ -424,13 +415,13 @@ int create_irq(void) | |||
424 | out: | 415 | out: |
425 | spin_unlock_irqrestore(&vector_lock, flags); | 416 | spin_unlock_irqrestore(&vector_lock, flags); |
426 | if (irq >= 0) | 417 | if (irq >= 0) |
427 | dynamic_irq_init(irq); | 418 | irq_init_desc(irq); |
428 | return irq; | 419 | return irq; |
429 | } | 420 | } |
430 | 421 | ||
431 | void destroy_irq(unsigned int irq) | 422 | void destroy_irq(unsigned int irq) |
432 | { | 423 | { |
433 | dynamic_irq_cleanup(irq); | 424 | irq_init_desc(irq); |
434 | clear_irq_vector(irq); | 425 | clear_irq_vector(irq); |
435 | } | 426 | } |
436 | 427 | ||
diff --git a/arch/mips/pci/msi-xlp.c b/arch/mips/pci/msi-xlp.c index afd8405e0188..3249685e03ad 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 = { | |||
206 | .irq_unmask = unmask_msi_irq, | 206 | .irq_unmask = unmask_msi_irq, |
207 | }; | 207 | }; |
208 | 208 | ||
209 | void destroy_irq(unsigned int irq) | ||
210 | { | ||
211 | /* nothing to do yet */ | ||
212 | } | ||
213 | |||
214 | void arch_teardown_msi_irq(unsigned int irq) | 209 | void arch_teardown_msi_irq(unsigned int irq) |
215 | { | 210 | { |
216 | destroy_irq(irq); | ||
217 | } | 211 | } |
218 | 212 | ||
219 | /* | 213 | /* |
@@ -298,10 +292,8 @@ static int xlp_setup_msi(uint64_t lnkbase, int node, int link, | |||
298 | 292 | ||
299 | xirq = xirq + msivec; /* msi mapped to global irq space */ | 293 | xirq = xirq + msivec; /* msi mapped to global irq space */ |
300 | ret = irq_set_msi_desc(xirq, desc); | 294 | ret = irq_set_msi_desc(xirq, desc); |
301 | if (ret < 0) { | 295 | if (ret < 0) |
302 | destroy_irq(xirq); | ||
303 | return ret; | 296 | return ret; |
304 | } | ||
305 | 297 | ||
306 | write_msi_msg(xirq, &msg); | 298 | write_msi_msg(xirq, &msg); |
307 | return 0; | 299 | return 0; |
diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c index 4427abbd48b5..0dde80332d3a 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) | |||
214 | } | 214 | } |
215 | 215 | ||
216 | #ifdef CONFIG_PCI_MSI | 216 | #ifdef CONFIG_PCI_MSI |
217 | void destroy_irq(unsigned int irq) | ||
218 | { | ||
219 | /* nothing to do yet */ | ||
220 | } | ||
221 | |||
222 | void arch_teardown_msi_irq(unsigned int irq) | 217 | void arch_teardown_msi_irq(unsigned int irq) |
223 | { | 218 | { |
224 | destroy_irq(irq); | ||
225 | } | 219 | } |
226 | 220 | ||
227 | int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) | 221 | 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) | |||
263 | MSI_DATA_DELIVERY_FIXED; | 257 | MSI_DATA_DELIVERY_FIXED; |
264 | 258 | ||
265 | ret = irq_set_msi_desc(irq, desc); | 259 | ret = irq_set_msi_desc(irq, desc); |
266 | if (ret < 0) { | 260 | if (ret < 0) |
267 | destroy_irq(irq); | ||
268 | return ret; | 261 | return ret; |
269 | } | ||
270 | 262 | ||
271 | write_msi_msg(irq, &msg); | 263 | write_msi_msg(irq, &msg); |
272 | return 0; | 264 | return 0; |
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index c7463aa0014b..99b0b09646ca 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] = { | |||
92 | 92 | ||
93 | void __init init_IRQ(void) | 93 | void __init init_IRQ(void) |
94 | { | 94 | { |
95 | irq_reserve_irqs(0, THIN_INTERRUPT); | ||
96 | init_cio_interrupts(); | 95 | init_cio_interrupts(); |
97 | init_airq_interrupts(); | 96 | init_airq_interrupts(); |
98 | init_ext_interrupts(); | 97 | init_ext_interrupts(); |
@@ -151,9 +150,9 @@ out: | |||
151 | return 0; | 150 | return 0; |
152 | } | 151 | } |
153 | 152 | ||
154 | int arch_show_interrupts(struct seq_file *p, int prec) | 153 | unsigned int arch_dynirq_lower_bound(unsigned int from) |
155 | { | 154 | { |
156 | return 0; | 155 | return from < THIN_INTERRUPT ? THIN_INTERRUPT : from; |
157 | } | 156 | } |
158 | 157 | ||
159 | /* | 158 | /* |
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index bdf02570d1df..9ddc51eeb8d6 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) | |||
401 | int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | 401 | int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) |
402 | { | 402 | { |
403 | struct zpci_dev *zdev = get_zdev(pdev); | 403 | struct zpci_dev *zdev = get_zdev(pdev); |
404 | unsigned int hwirq, irq, msi_vecs; | 404 | unsigned int hwirq, msi_vecs; |
405 | unsigned long aisb; | 405 | unsigned long aisb; |
406 | struct msi_desc *msi; | 406 | struct msi_desc *msi; |
407 | struct msi_msg msg; | 407 | struct msi_msg msg; |
408 | int rc; | 408 | int rc, irq; |
409 | 409 | ||
410 | if (type == PCI_CAP_ID_MSI && nvec > 1) | 410 | if (type == PCI_CAP_ID_MSI && nvec > 1) |
411 | return 1; | 411 | return 1; |
@@ -433,7 +433,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
433 | list_for_each_entry(msi, &pdev->msi_list, list) { | 433 | list_for_each_entry(msi, &pdev->msi_list, list) { |
434 | rc = -EIO; | 434 | rc = -EIO; |
435 | irq = irq_alloc_desc(0); /* Alloc irq on node 0 */ | 435 | irq = irq_alloc_desc(0); /* Alloc irq on node 0 */ |
436 | if (irq == NO_IRQ) | 436 | if (irq < 0) |
437 | goto out_msi; | 437 | goto out_msi; |
438 | rc = irq_set_msi_desc(irq, msi); | 438 | rc = irq_set_msi_desc(irq, msi); |
439 | if (rc) | 439 | if (rc) |
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 85258ca43ff5..4f3006b600e3 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig | |||
@@ -125,6 +125,8 @@ config HVC_TILE | |||
125 | 125 | ||
126 | config TILEGX | 126 | config TILEGX |
127 | bool "Building for TILE-Gx (64-bit) processor" | 127 | bool "Building for TILE-Gx (64-bit) processor" |
128 | select SPARSE_IRQ | ||
129 | select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ | ||
128 | select HAVE_FUNCTION_TRACER | 130 | select HAVE_FUNCTION_TRACER |
129 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST | 131 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST |
130 | select HAVE_FUNCTION_GRAPH_TRACER | 132 | select HAVE_FUNCTION_GRAPH_TRACER |
diff --git a/arch/tile/include/asm/irq.h b/arch/tile/include/asm/irq.h index 33cff9a3058b..1fe86911838b 100644 --- a/arch/tile/include/asm/irq.h +++ b/arch/tile/include/asm/irq.h | |||
@@ -18,10 +18,12 @@ | |||
18 | #include <linux/hardirq.h> | 18 | #include <linux/hardirq.h> |
19 | 19 | ||
20 | /* The hypervisor interface provides 32 IRQs. */ | 20 | /* The hypervisor interface provides 32 IRQs. */ |
21 | #define NR_IRQS 32 | 21 | #define NR_IRQS 32 |
22 | 22 | ||
23 | /* IRQ numbers used for linux IPIs. */ | 23 | /* IRQ numbers used for linux IPIs. */ |
24 | #define IRQ_RESCHEDULE 0 | 24 | #define IRQ_RESCHEDULE 0 |
25 | /* Interrupts for dynamic allocation start at 1. Let the core allocate irq0 */ | ||
26 | #define NR_IRQS_LEGACY 1 | ||
25 | 27 | ||
26 | #define irq_canonicalize(irq) (irq) | 28 | #define irq_canonicalize(irq) (irq) |
27 | 29 | ||
diff --git a/arch/tile/kernel/irq.c b/arch/tile/kernel/irq.c index 906a76bdb31d..637f2ffaa5f5 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) | |||
54 | */ | 54 | */ |
55 | static DEFINE_PER_CPU(int, irq_depth); | 55 | static DEFINE_PER_CPU(int, irq_depth); |
56 | 56 | ||
57 | /* State for allocating IRQs on Gx. */ | ||
58 | #if CHIP_HAS_IPI() | ||
59 | static unsigned long available_irqs = ((1UL << NR_IRQS) - 1) & | ||
60 | (~(1UL << IRQ_RESCHEDULE)); | ||
61 | static DEFINE_SPINLOCK(available_irqs_lock); | ||
62 | #endif | ||
63 | |||
64 | #if CHIP_HAS_IPI() | 57 | #if CHIP_HAS_IPI() |
65 | /* Use SPRs to manipulate device interrupts. */ | 58 | /* Use SPRs to manipulate device interrupts. */ |
66 | #define mask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_SET_K, irq_mask) | 59 | #define mask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_SET_K, irq_mask) |
@@ -278,38 +271,11 @@ int arch_show_interrupts(struct seq_file *p, int prec) | |||
278 | return 0; | 271 | return 0; |
279 | } | 272 | } |
280 | 273 | ||
281 | /* | ||
282 | * Generic, controller-independent functions: | ||
283 | */ | ||
284 | |||
285 | #if CHIP_HAS_IPI() | 274 | #if CHIP_HAS_IPI() |
286 | int create_irq(void) | 275 | int arch_setup_hwirq(unsigned int irq, int node) |
287 | { | 276 | { |
288 | unsigned long flags; | 277 | return irq >= NR_IRQS ? -EINVAL : 0; |
289 | int result; | ||
290 | |||
291 | spin_lock_irqsave(&available_irqs_lock, flags); | ||
292 | if (available_irqs == 0) | ||
293 | result = -ENOMEM; | ||
294 | else { | ||
295 | result = __ffs(available_irqs); | ||
296 | available_irqs &= ~(1UL << result); | ||
297 | dynamic_irq_init(result); | ||
298 | } | ||
299 | spin_unlock_irqrestore(&available_irqs_lock, flags); | ||
300 | |||
301 | return result; | ||
302 | } | 278 | } |
303 | EXPORT_SYMBOL(create_irq); | ||
304 | 279 | ||
305 | void destroy_irq(unsigned int irq) | 280 | void arch_teardown_hwirq(unsigned int irq) { } |
306 | { | ||
307 | unsigned long flags; | ||
308 | |||
309 | spin_lock_irqsave(&available_irqs_lock, flags); | ||
310 | available_irqs |= (1UL << irq); | ||
311 | dynamic_irq_cleanup(irq); | ||
312 | spin_unlock_irqrestore(&available_irqs_lock, flags); | ||
313 | } | ||
314 | EXPORT_SYMBOL(destroy_irq); | ||
315 | #endif | 281 | #endif |
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c index 077b7bc437e5..e39f9c542807 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) | |||
350 | int cpu; | 350 | int cpu; |
351 | 351 | ||
352 | /* Ask the kernel to allocate an IRQ. */ | 352 | /* Ask the kernel to allocate an IRQ. */ |
353 | irq = create_irq(); | 353 | irq = irq_alloc_hwirq(-1); |
354 | if (irq < 0) { | 354 | if (!irq) { |
355 | pr_err("PCI: no free irq vectors, failed for %d\n", i); | 355 | pr_err("PCI: no free irq vectors, failed for %d\n", i); |
356 | |||
357 | goto free_irqs; | 356 | goto free_irqs; |
358 | } | 357 | } |
359 | controller->irq_intx_table[i] = irq; | 358 | controller->irq_intx_table[i] = irq; |
@@ -382,7 +381,7 @@ static int tile_init_irqs(struct pci_controller *controller) | |||
382 | 381 | ||
383 | free_irqs: | 382 | free_irqs: |
384 | for (j = 0; j < i; j++) | 383 | for (j = 0; j < i; j++) |
385 | destroy_irq(controller->irq_intx_table[j]); | 384 | irq_free_hwirq(controller->irq_intx_table[j]); |
386 | 385 | ||
387 | return -1; | 386 | return -1; |
388 | } | 387 | } |
@@ -1500,9 +1499,9 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) | |||
1500 | int irq; | 1499 | int irq; |
1501 | int ret; | 1500 | int ret; |
1502 | 1501 | ||
1503 | irq = create_irq(); | 1502 | irq = irq_alloc_hwirq(-1); |
1504 | if (irq < 0) | 1503 | if (!irq) |
1505 | return irq; | 1504 | return -ENOSPC; |
1506 | 1505 | ||
1507 | /* | 1506 | /* |
1508 | * Since we use a 64-bit Mem-Map to accept the MSI write, we fail | 1507 | * Since we use a 64-bit Mem-Map to accept the MSI write, we fail |
@@ -1601,11 +1600,11 @@ hv_msi_config_failure: | |||
1601 | /* Free mem-map */ | 1600 | /* Free mem-map */ |
1602 | msi_mem_map_alloc_failure: | 1601 | msi_mem_map_alloc_failure: |
1603 | is_64_failure: | 1602 | is_64_failure: |
1604 | destroy_irq(irq); | 1603 | irq_free_hwirq(irq); |
1605 | return ret; | 1604 | return ret; |
1606 | } | 1605 | } |
1607 | 1606 | ||
1608 | void arch_teardown_msi_irq(unsigned int irq) | 1607 | void arch_teardown_msi_irq(unsigned int irq) |
1609 | { | 1608 | { |
1610 | destroy_irq(irq); | 1609 | irq_free_hwirq(irq); |
1611 | } | 1610 | } |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7d5feb5908dd..7a01d4335029 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -833,6 +833,7 @@ config X86_LOCAL_APIC | |||
833 | config X86_IO_APIC | 833 | config X86_IO_APIC |
834 | def_bool y | 834 | def_bool y |
835 | depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC || PCI_MSI | 835 | depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC || PCI_MSI |
836 | select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ | ||
836 | 837 | ||
837 | config X86_REROUTE_FOR_BROKEN_BOOT_IRQS | 838 | config X86_REROUTE_FOR_BROKEN_BOOT_IRQS |
838 | bool "Reroute for broken boot IRQs" | 839 | bool "Reroute for broken boot IRQs" |
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index 459e50a424d1..90f97b4b9347 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); | |||
168 | extern void mask_ioapic_entries(void); | 168 | extern void mask_ioapic_entries(void); |
169 | extern int restore_ioapic_entries(void); | 169 | extern int restore_ioapic_entries(void); |
170 | 170 | ||
171 | extern int get_nr_irqs_gsi(void); | ||
172 | |||
173 | extern void setup_ioapic_ids_from_mpc(void); | 171 | extern void setup_ioapic_ids_from_mpc(void); |
174 | extern void setup_ioapic_ids_from_mpc_nocheck(void); | 172 | extern void setup_ioapic_ids_from_mpc_nocheck(void); |
175 | 173 | ||
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h index d806b228d2c0..b7747c4c2cf2 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, | |||
103 | } | 103 | } |
104 | #endif /* CONFIG_IRQ_REMAP */ | 104 | #endif /* CONFIG_IRQ_REMAP */ |
105 | 105 | ||
106 | #define dmar_alloc_hwirq() irq_alloc_hwirq(-1) | ||
107 | #define dmar_free_hwirq irq_free_hwirq | ||
108 | |||
106 | #endif /* __X86_IRQ_REMAPPING_H */ | 109 | #endif /* __X86_IRQ_REMAPPING_H */ |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 992060e09897..9d0a9795a0f8 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) | |||
206 | count = ARRAY_SIZE(irq_cfgx); | 206 | count = ARRAY_SIZE(irq_cfgx); |
207 | node = cpu_to_node(0); | 207 | node = cpu_to_node(0); |
208 | 208 | ||
209 | /* Make sure the legacy interrupts are marked in the bitmap */ | ||
210 | irq_reserve_irqs(0, legacy_pic->nr_legacy_irqs); | ||
211 | |||
212 | for (i = 0; i < count; i++) { | 209 | for (i = 0; i < count; i++) { |
213 | irq_set_chip_data(i, &cfg[i]); | 210 | irq_set_chip_data(i, &cfg[i]); |
214 | zalloc_cpumask_var_node(&cfg[i].domain, GFP_KERNEL, node); | 211 | zalloc_cpumask_var_node(&cfg[i].domain, GFP_KERNEL, node); |
@@ -281,18 +278,6 @@ static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node) | |||
281 | return cfg; | 278 | return cfg; |
282 | } | 279 | } |
283 | 280 | ||
284 | static int alloc_irqs_from(unsigned int from, unsigned int count, int node) | ||
285 | { | ||
286 | return irq_alloc_descs_from(from, count, node); | ||
287 | } | ||
288 | |||
289 | static void free_irq_at(unsigned int at, struct irq_cfg *cfg) | ||
290 | { | ||
291 | free_irq_cfg(at, cfg); | ||
292 | irq_free_desc(at); | ||
293 | } | ||
294 | |||
295 | |||
296 | struct io_apic { | 281 | struct io_apic { |
297 | unsigned int index; | 282 | unsigned int index; |
298 | unsigned int unused[3]; | 283 | unsigned int unused[3]; |
@@ -2916,98 +2901,39 @@ static int __init ioapic_init_ops(void) | |||
2916 | device_initcall(ioapic_init_ops); | 2901 | device_initcall(ioapic_init_ops); |
2917 | 2902 | ||
2918 | /* | 2903 | /* |
2919 | * Dynamic irq allocate and deallocation | 2904 | * Dynamic irq allocate and deallocation. Should be replaced by irq domains! |
2920 | */ | 2905 | */ |
2921 | unsigned int __create_irqs(unsigned int from, unsigned int count, int node) | 2906 | int arch_setup_hwirq(unsigned int irq, int node) |
2922 | { | 2907 | { |
2923 | struct irq_cfg **cfg; | 2908 | struct irq_cfg *cfg; |
2924 | unsigned long flags; | 2909 | unsigned long flags; |
2925 | int irq, i; | 2910 | int ret; |
2926 | |||
2927 | if (from < nr_irqs_gsi) | ||
2928 | from = nr_irqs_gsi; | ||
2929 | 2911 | ||
2930 | cfg = kzalloc_node(count * sizeof(cfg[0]), GFP_KERNEL, node); | 2912 | cfg = alloc_irq_cfg(irq, node); |
2931 | if (!cfg) | 2913 | if (!cfg) |
2932 | return 0; | 2914 | return -ENOMEM; |
2933 | |||
2934 | irq = alloc_irqs_from(from, count, node); | ||
2935 | if (irq < 0) | ||
2936 | goto out_cfgs; | ||
2937 | |||
2938 | for (i = 0; i < count; i++) { | ||
2939 | cfg[i] = alloc_irq_cfg(irq + i, node); | ||
2940 | if (!cfg[i]) | ||
2941 | goto out_irqs; | ||
2942 | } | ||
2943 | 2915 | ||
2944 | raw_spin_lock_irqsave(&vector_lock, flags); | 2916 | raw_spin_lock_irqsave(&vector_lock, flags); |
2945 | for (i = 0; i < count; i++) | 2917 | ret = __assign_irq_vector(irq, cfg, apic->target_cpus()); |
2946 | if (__assign_irq_vector(irq + i, cfg[i], apic->target_cpus())) | ||
2947 | goto out_vecs; | ||
2948 | raw_spin_unlock_irqrestore(&vector_lock, flags); | ||
2949 | |||
2950 | for (i = 0; i < count; i++) { | ||
2951 | irq_set_chip_data(irq + i, cfg[i]); | ||
2952 | irq_clear_status_flags(irq + i, IRQ_NOREQUEST); | ||
2953 | } | ||
2954 | |||
2955 | kfree(cfg); | ||
2956 | return irq; | ||
2957 | |||
2958 | out_vecs: | ||
2959 | for (i--; i >= 0; i--) | ||
2960 | __clear_irq_vector(irq + i, cfg[i]); | ||
2961 | raw_spin_unlock_irqrestore(&vector_lock, flags); | 2918 | raw_spin_unlock_irqrestore(&vector_lock, flags); |
2962 | out_irqs: | ||
2963 | for (i = 0; i < count; i++) | ||
2964 | free_irq_at(irq + i, cfg[i]); | ||
2965 | out_cfgs: | ||
2966 | kfree(cfg); | ||
2967 | return 0; | ||
2968 | } | ||
2969 | 2919 | ||
2970 | unsigned int create_irq_nr(unsigned int from, int node) | 2920 | if (!ret) |
2971 | { | 2921 | irq_set_chip_data(irq, cfg); |
2972 | return __create_irqs(from, 1, node); | 2922 | else |
2973 | } | 2923 | free_irq_cfg(irq, cfg); |
2974 | 2924 | return ret; | |
2975 | int create_irq(void) | ||
2976 | { | ||
2977 | int node = cpu_to_node(0); | ||
2978 | unsigned int irq_want; | ||
2979 | int irq; | ||
2980 | |||
2981 | irq_want = nr_irqs_gsi; | ||
2982 | irq = create_irq_nr(irq_want, node); | ||
2983 | |||
2984 | if (irq == 0) | ||
2985 | irq = -1; | ||
2986 | |||
2987 | return irq; | ||
2988 | } | 2925 | } |
2989 | 2926 | ||
2990 | void destroy_irq(unsigned int irq) | 2927 | void arch_teardown_hwirq(unsigned int irq) |
2991 | { | 2928 | { |
2992 | struct irq_cfg *cfg = irq_get_chip_data(irq); | 2929 | struct irq_cfg *cfg = irq_get_chip_data(irq); |
2993 | unsigned long flags; | 2930 | unsigned long flags; |
2994 | 2931 | ||
2995 | irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE); | ||
2996 | |||
2997 | free_remapped_irq(irq); | 2932 | free_remapped_irq(irq); |
2998 | |||
2999 | raw_spin_lock_irqsave(&vector_lock, flags); | 2933 | raw_spin_lock_irqsave(&vector_lock, flags); |
3000 | __clear_irq_vector(irq, cfg); | 2934 | __clear_irq_vector(irq, cfg); |
3001 | raw_spin_unlock_irqrestore(&vector_lock, flags); | 2935 | raw_spin_unlock_irqrestore(&vector_lock, flags); |
3002 | free_irq_at(irq, cfg); | 2936 | free_irq_cfg(irq, cfg); |
3003 | } | ||
3004 | |||
3005 | void destroy_irqs(unsigned int irq, unsigned int count) | ||
3006 | { | ||
3007 | unsigned int i; | ||
3008 | |||
3009 | for (i = 0; i < count; i++) | ||
3010 | destroy_irq(irq + i); | ||
3011 | } | 2937 | } |
3012 | 2938 | ||
3013 | /* | 2939 | /* |
@@ -3136,8 +3062,8 @@ int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, | |||
3136 | 3062 | ||
3137 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | 3063 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) |
3138 | { | 3064 | { |
3139 | unsigned int irq, irq_want; | ||
3140 | struct msi_desc *msidesc; | 3065 | struct msi_desc *msidesc; |
3066 | unsigned int irq; | ||
3141 | int node, ret; | 3067 | int node, ret; |
3142 | 3068 | ||
3143 | /* Multiple MSI vectors only supported with interrupt remapping */ | 3069 | /* Multiple MSI vectors only supported with interrupt remapping */ |
@@ -3145,28 +3071,25 @@ int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
3145 | return 1; | 3071 | return 1; |
3146 | 3072 | ||
3147 | node = dev_to_node(&dev->dev); | 3073 | node = dev_to_node(&dev->dev); |
3148 | irq_want = nr_irqs_gsi; | 3074 | |
3149 | list_for_each_entry(msidesc, &dev->msi_list, list) { | 3075 | list_for_each_entry(msidesc, &dev->msi_list, list) { |
3150 | irq = create_irq_nr(irq_want, node); | 3076 | irq = irq_alloc_hwirq(node); |
3151 | if (irq == 0) | 3077 | if (!irq) |
3152 | return -ENOSPC; | 3078 | return -ENOSPC; |
3153 | 3079 | ||
3154 | irq_want = irq + 1; | ||
3155 | |||
3156 | ret = setup_msi_irq(dev, msidesc, irq, 0); | 3080 | ret = setup_msi_irq(dev, msidesc, irq, 0); |
3157 | if (ret < 0) | 3081 | if (ret < 0) { |
3158 | goto error; | 3082 | irq_free_hwirq(irq); |
3083 | return ret; | ||
3084 | } | ||
3085 | |||
3159 | } | 3086 | } |
3160 | return 0; | 3087 | return 0; |
3161 | |||
3162 | error: | ||
3163 | destroy_irq(irq); | ||
3164 | return ret; | ||
3165 | } | 3088 | } |
3166 | 3089 | ||
3167 | void native_teardown_msi_irq(unsigned int irq) | 3090 | void native_teardown_msi_irq(unsigned int irq) |
3168 | { | 3091 | { |
3169 | destroy_irq(irq); | 3092 | irq_free_hwirq(irq); |
3170 | } | 3093 | } |
3171 | 3094 | ||
3172 | #ifdef CONFIG_DMAR_TABLE | 3095 | #ifdef CONFIG_DMAR_TABLE |
@@ -3420,11 +3343,6 @@ static void __init probe_nr_irqs_gsi(void) | |||
3420 | printk(KERN_DEBUG "nr_irqs_gsi: %d\n", nr_irqs_gsi); | 3343 | printk(KERN_DEBUG "nr_irqs_gsi: %d\n", nr_irqs_gsi); |
3421 | } | 3344 | } |
3422 | 3345 | ||
3423 | int get_nr_irqs_gsi(void) | ||
3424 | { | ||
3425 | return nr_irqs_gsi; | ||
3426 | } | ||
3427 | |||
3428 | unsigned int arch_dynirq_lower_bound(unsigned int from) | 3346 | unsigned int arch_dynirq_lower_bound(unsigned int from) |
3429 | { | 3347 | { |
3430 | return from < nr_irqs_gsi ? nr_irqs_gsi : from; | 3348 | return from < nr_irqs_gsi ? nr_irqs_gsi : from; |
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 4177bfbc80b0..5f5a147d1cd2 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, | |||
479 | static int hpet_setup_msi_irq(unsigned int irq) | 479 | static int hpet_setup_msi_irq(unsigned int irq) |
480 | { | 480 | { |
481 | if (x86_msi.setup_hpet_msi(irq, hpet_blockid)) { | 481 | if (x86_msi.setup_hpet_msi(irq, hpet_blockid)) { |
482 | destroy_irq(irq); | 482 | irq_free_hwirq(irq); |
483 | return -EINVAL; | 483 | return -EINVAL; |
484 | } | 484 | } |
485 | return 0; | 485 | return 0; |
@@ -487,9 +487,8 @@ static int hpet_setup_msi_irq(unsigned int irq) | |||
487 | 487 | ||
488 | static int hpet_assign_irq(struct hpet_dev *dev) | 488 | static int hpet_assign_irq(struct hpet_dev *dev) |
489 | { | 489 | { |
490 | unsigned int irq; | 490 | unsigned int irq = irq_alloc_hwirq(-1); |
491 | 491 | ||
492 | irq = create_irq_nr(0, -1); | ||
493 | if (!irq) | 492 | if (!irq) |
494 | return -EINVAL; | 493 | return -EINVAL; |
495 | 494 | ||
diff --git a/arch/x86/platform/uv/uv_irq.c b/arch/x86/platform/uv/uv_irq.c index acf7752da952..b233681af4de 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, | |||
238 | int uv_setup_irq(char *irq_name, int cpu, int mmr_blade, | 238 | int uv_setup_irq(char *irq_name, int cpu, int mmr_blade, |
239 | unsigned long mmr_offset, int limit) | 239 | unsigned long mmr_offset, int limit) |
240 | { | 240 | { |
241 | int irq, ret; | 241 | int ret, irq = irq_alloc_hwirq(uv_blade_to_memory_nid(mmr_blade)); |
242 | 242 | ||
243 | irq = create_irq_nr(NR_IRQS_LEGACY, uv_blade_to_memory_nid(mmr_blade)); | 243 | if (!irq) |
244 | |||
245 | if (irq <= 0) | ||
246 | return -EBUSY; | 244 | return -EBUSY; |
247 | 245 | ||
248 | ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset, | 246 | 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, | |||
250 | if (ret == irq) | 248 | if (ret == irq) |
251 | uv_set_irq_2_mmr_info(irq, mmr_offset, mmr_blade); | 249 | uv_set_irq_2_mmr_info(irq, mmr_offset, mmr_blade); |
252 | else | 250 | else |
253 | destroy_irq(irq); | 251 | irq_free_hwirq(irq); |
254 | 252 | ||
255 | return ret; | 253 | return ret; |
256 | } | 254 | } |
@@ -285,6 +283,6 @@ void uv_teardown_irq(unsigned int irq) | |||
285 | n = n->rb_right; | 283 | n = n->rb_right; |
286 | } | 284 | } |
287 | spin_unlock_irqrestore(&uv_irq_lock, irqflags); | 285 | spin_unlock_irqrestore(&uv_irq_lock, irqflags); |
288 | destroy_irq(irq); | 286 | irq_free_hwirq(irq); |
289 | } | 287 | } |
290 | EXPORT_SYMBOL_GPL(uv_teardown_irq); | 288 | EXPORT_SYMBOL_GPL(uv_teardown_irq); |
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 39f8b717fe84..9a4f05e5b23f 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c | |||
@@ -994,7 +994,7 @@ static void free_iommu(struct intel_iommu *iommu) | |||
994 | if (iommu->irq) { | 994 | if (iommu->irq) { |
995 | free_irq(iommu->irq, iommu); | 995 | free_irq(iommu->irq, iommu); |
996 | irq_set_handler_data(iommu->irq, NULL); | 996 | irq_set_handler_data(iommu->irq, NULL); |
997 | destroy_irq(iommu->irq); | 997 | dmar_free_hwirq(iommu->irq); |
998 | } | 998 | } |
999 | 999 | ||
1000 | if (iommu->qi) { | 1000 | if (iommu->qi) { |
@@ -1550,8 +1550,8 @@ int dmar_set_interrupt(struct intel_iommu *iommu) | |||
1550 | if (iommu->irq) | 1550 | if (iommu->irq) |
1551 | return 0; | 1551 | return 0; |
1552 | 1552 | ||
1553 | irq = create_irq(); | 1553 | irq = dmar_alloc_hwirq(); |
1554 | if (!irq) { | 1554 | if (irq <= 0) { |
1555 | pr_err("IOMMU: no free vectors\n"); | 1555 | pr_err("IOMMU: no free vectors\n"); |
1556 | return -EINVAL; | 1556 | return -EINVAL; |
1557 | } | 1557 | } |
@@ -1563,7 +1563,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu) | |||
1563 | if (ret) { | 1563 | if (ret) { |
1564 | irq_set_handler_data(irq, NULL); | 1564 | irq_set_handler_data(irq, NULL); |
1565 | iommu->irq = 0; | 1565 | iommu->irq = 0; |
1566 | destroy_irq(irq); | 1566 | dmar_free_hwirq(irq); |
1567 | return ret; | 1567 | return ret; |
1568 | } | 1568 | } |
1569 | 1569 | ||
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 228632c99adb..33c439524080 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) | |||
51 | 51 | ||
52 | static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) | 52 | static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) |
53 | { | 53 | { |
54 | int node, ret, sub_handle, nvec_pow2, index = 0; | 54 | int ret, sub_handle, nvec_pow2, index = 0; |
55 | unsigned int irq; | 55 | unsigned int irq; |
56 | struct msi_desc *msidesc; | 56 | struct msi_desc *msidesc; |
57 | 57 | ||
@@ -61,8 +61,7 @@ static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) | |||
61 | WARN_ON(msidesc->msi_attrib.multiple); | 61 | WARN_ON(msidesc->msi_attrib.multiple); |
62 | WARN_ON(msidesc->nvec_used); | 62 | WARN_ON(msidesc->nvec_used); |
63 | 63 | ||
64 | node = dev_to_node(&dev->dev); | 64 | irq = irq_alloc_hwirqs(nvec, dev_to_node(&dev->dev)); |
65 | irq = __create_irqs(get_nr_irqs_gsi(), nvec, node); | ||
66 | if (irq == 0) | 65 | if (irq == 0) |
67 | return -ENOSPC; | 66 | return -ENOSPC; |
68 | 67 | ||
@@ -89,7 +88,7 @@ static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) | |||
89 | return 0; | 88 | return 0; |
90 | 89 | ||
91 | error: | 90 | error: |
92 | destroy_irqs(irq, nvec); | 91 | irq_free_hwirqs(irq, nvec); |
93 | 92 | ||
94 | /* | 93 | /* |
95 | * Restore altered MSI descriptor fields and prevent just destroyed | 94 | * 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) | |||
109 | unsigned int irq; | 108 | unsigned int irq; |
110 | 109 | ||
111 | node = dev_to_node(&dev->dev); | 110 | node = dev_to_node(&dev->dev); |
112 | irq = get_nr_irqs_gsi(); | ||
113 | sub_handle = 0; | 111 | sub_handle = 0; |
114 | 112 | ||
115 | list_for_each_entry(msidesc, &dev->msi_list, list) { | 113 | list_for_each_entry(msidesc, &dev->msi_list, list) { |
116 | 114 | ||
117 | irq = create_irq_nr(irq, node); | 115 | irq = irq_alloc_hwirq(node); |
118 | if (irq == 0) | 116 | if (irq == 0) |
119 | return -1; | 117 | return -1; |
120 | 118 | ||
@@ -137,7 +135,7 @@ static int do_setup_msix_irqs(struct pci_dev *dev, int nvec) | |||
137 | return 0; | 135 | return 0; |
138 | 136 | ||
139 | error: | 137 | error: |
140 | destroy_irq(irq); | 138 | irq_free_hwirq(irq); |
141 | return ret; | 139 | return ret; |
142 | } | 140 | } |
143 | 141 | ||
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index d770f7406631..bbb746e35500 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig | |||
@@ -30,6 +30,12 @@ config ARM_VIC_NR | |||
30 | The maximum number of VICs available in the system, for | 30 | The maximum number of VICs available in the system, for |
31 | power management. | 31 | power management. |
32 | 32 | ||
33 | config BRCMSTB_L2_IRQ | ||
34 | bool | ||
35 | depends on ARM | ||
36 | select GENERIC_IRQ_CHIP | ||
37 | select IRQ_DOMAIN | ||
38 | |||
33 | config DW_APB_ICTL | 39 | config DW_APB_ICTL |
34 | bool | 40 | bool |
35 | select IRQ_DOMAIN | 41 | select IRQ_DOMAIN |
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index f180f8d5fb7b..62a13e5ef98f 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -29,3 +29,4 @@ obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o | |||
29 | obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o | 29 | obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o |
30 | obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o | 30 | obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o |
31 | obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o | 31 | obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o |
32 | 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 000000000000..8ee2a36d5840 --- /dev/null +++ b/drivers/irqchip/irq-brcmstb-l2.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * Generic Broadcom Set Top Box Level 2 Interrupt controller driver | ||
3 | * | ||
4 | * Copyright (C) 2014 Broadcom Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
17 | |||
18 | #include <linux/init.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/of_irq.h> | ||
24 | #include <linux/of_address.h> | ||
25 | #include <linux/of_platform.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/irq.h> | ||
28 | #include <linux/io.h> | ||
29 | #include <linux/irqdomain.h> | ||
30 | #include <linux/irqchip.h> | ||
31 | #include <linux/irqchip/chained_irq.h> | ||
32 | |||
33 | #include <asm/mach/irq.h> | ||
34 | |||
35 | #include "irqchip.h" | ||
36 | |||
37 | /* Register offsets in the L2 interrupt controller */ | ||
38 | #define CPU_STATUS 0x00 | ||
39 | #define CPU_SET 0x04 | ||
40 | #define CPU_CLEAR 0x08 | ||
41 | #define CPU_MASK_STATUS 0x0c | ||
42 | #define CPU_MASK_SET 0x10 | ||
43 | #define CPU_MASK_CLEAR 0x14 | ||
44 | |||
45 | /* L2 intc private data structure */ | ||
46 | struct brcmstb_l2_intc_data { | ||
47 | int parent_irq; | ||
48 | void __iomem *base; | ||
49 | struct irq_domain *domain; | ||
50 | bool can_wake; | ||
51 | u32 saved_mask; /* for suspend/resume */ | ||
52 | }; | ||
53 | |||
54 | static void brcmstb_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) | ||
55 | { | ||
56 | struct brcmstb_l2_intc_data *b = irq_desc_get_handler_data(desc); | ||
57 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
58 | u32 status; | ||
59 | |||
60 | chained_irq_enter(chip, desc); | ||
61 | |||
62 | status = __raw_readl(b->base + CPU_STATUS) & | ||
63 | ~(__raw_readl(b->base + CPU_MASK_STATUS)); | ||
64 | |||
65 | if (status == 0) { | ||
66 | do_bad_IRQ(irq, desc); | ||
67 | goto out; | ||
68 | } | ||
69 | |||
70 | do { | ||
71 | irq = ffs(status) - 1; | ||
72 | /* ack at our level */ | ||
73 | __raw_writel(1 << irq, b->base + CPU_CLEAR); | ||
74 | status &= ~(1 << irq); | ||
75 | generic_handle_irq(irq_find_mapping(b->domain, irq)); | ||
76 | } while (status); | ||
77 | out: | ||
78 | chained_irq_exit(chip, desc); | ||
79 | } | ||
80 | |||
81 | static void brcmstb_l2_intc_suspend(struct irq_data *d) | ||
82 | { | ||
83 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
84 | struct brcmstb_l2_intc_data *b = gc->private; | ||
85 | |||
86 | irq_gc_lock(gc); | ||
87 | /* Save the current mask */ | ||
88 | b->saved_mask = __raw_readl(b->base + CPU_MASK_STATUS); | ||
89 | |||
90 | if (b->can_wake) { | ||
91 | /* Program the wakeup mask */ | ||
92 | __raw_writel(~gc->wake_active, b->base + CPU_MASK_SET); | ||
93 | __raw_writel(gc->wake_active, b->base + CPU_MASK_CLEAR); | ||
94 | } | ||
95 | irq_gc_unlock(gc); | ||
96 | } | ||
97 | |||
98 | static void brcmstb_l2_intc_resume(struct irq_data *d) | ||
99 | { | ||
100 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
101 | struct brcmstb_l2_intc_data *b = gc->private; | ||
102 | |||
103 | irq_gc_lock(gc); | ||
104 | /* Clear unmasked non-wakeup interrupts */ | ||
105 | __raw_writel(~b->saved_mask & ~gc->wake_active, b->base + CPU_CLEAR); | ||
106 | |||
107 | /* Restore the saved mask */ | ||
108 | __raw_writel(b->saved_mask, b->base + CPU_MASK_SET); | ||
109 | __raw_writel(~b->saved_mask, b->base + CPU_MASK_CLEAR); | ||
110 | irq_gc_unlock(gc); | ||
111 | } | ||
112 | |||
113 | int __init brcmstb_l2_intc_of_init(struct device_node *np, | ||
114 | struct device_node *parent) | ||
115 | { | ||
116 | unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; | ||
117 | struct brcmstb_l2_intc_data *data; | ||
118 | struct irq_chip_generic *gc; | ||
119 | struct irq_chip_type *ct; | ||
120 | int ret; | ||
121 | |||
122 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
123 | if (!data) | ||
124 | return -ENOMEM; | ||
125 | |||
126 | data->base = of_iomap(np, 0); | ||
127 | if (!data->base) { | ||
128 | pr_err("failed to remap intc L2 registers\n"); | ||
129 | ret = -ENOMEM; | ||
130 | goto out_free; | ||
131 | } | ||
132 | |||
133 | /* Disable all interrupts by default */ | ||
134 | __raw_writel(0xffffffff, data->base + CPU_MASK_SET); | ||
135 | __raw_writel(0xffffffff, data->base + CPU_CLEAR); | ||
136 | |||
137 | data->parent_irq = irq_of_parse_and_map(np, 0); | ||
138 | if (data->parent_irq < 0) { | ||
139 | pr_err("failed to find parent interrupt\n"); | ||
140 | ret = data->parent_irq; | ||
141 | goto out_unmap; | ||
142 | } | ||
143 | |||
144 | data->domain = irq_domain_add_linear(np, 32, | ||
145 | &irq_generic_chip_ops, NULL); | ||
146 | if (!data->domain) { | ||
147 | ret = -ENOMEM; | ||
148 | goto out_unmap; | ||
149 | } | ||
150 | |||
151 | /* Allocate a single Generic IRQ chip for this node */ | ||
152 | ret = irq_alloc_domain_generic_chips(data->domain, 32, 1, | ||
153 | np->full_name, handle_level_irq, clr, 0, 0); | ||
154 | if (ret) { | ||
155 | pr_err("failed to allocate generic irq chip\n"); | ||
156 | goto out_free_domain; | ||
157 | } | ||
158 | |||
159 | /* Set the IRQ chaining logic */ | ||
160 | irq_set_handler_data(data->parent_irq, data); | ||
161 | irq_set_chained_handler(data->parent_irq, brcmstb_l2_intc_irq_handle); | ||
162 | |||
163 | gc = irq_get_domain_generic_chip(data->domain, 0); | ||
164 | gc->reg_base = data->base; | ||
165 | gc->private = data; | ||
166 | ct = gc->chip_types; | ||
167 | |||
168 | ct->chip.irq_ack = irq_gc_ack_set_bit; | ||
169 | ct->regs.ack = CPU_CLEAR; | ||
170 | |||
171 | ct->chip.irq_mask = irq_gc_mask_disable_reg; | ||
172 | ct->regs.disable = CPU_MASK_SET; | ||
173 | |||
174 | ct->chip.irq_unmask = irq_gc_unmask_enable_reg; | ||
175 | ct->regs.enable = CPU_MASK_CLEAR; | ||
176 | |||
177 | ct->chip.irq_suspend = brcmstb_l2_intc_suspend; | ||
178 | ct->chip.irq_resume = brcmstb_l2_intc_resume; | ||
179 | |||
180 | if (of_property_read_bool(np, "brcm,irq-can-wake")) { | ||
181 | data->can_wake = true; | ||
182 | /* This IRQ chip can wake the system, set all child interrupts | ||
183 | * in wake_enabled mask | ||
184 | */ | ||
185 | gc->wake_enabled = 0xffffffff; | ||
186 | ct->chip.irq_set_wake = irq_gc_set_wake; | ||
187 | } | ||
188 | |||
189 | pr_info("registered L2 intc (mem: 0x%p, parent irq: %d)\n", | ||
190 | data->base, data->parent_irq); | ||
191 | |||
192 | return 0; | ||
193 | |||
194 | out_free_domain: | ||
195 | irq_domain_remove(data->domain); | ||
196 | out_unmap: | ||
197 | iounmap(data->base); | ||
198 | out_free: | ||
199 | kfree(data); | ||
200 | return ret; | ||
201 | } | ||
202 | IRQCHIP_DECLARE(brcmstb_l2_intc, "brcm,l2-intc", brcmstb_l2_intc_of_init); | ||
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 57d165e026f4..7e11c9d6ae8c 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c | |||
@@ -291,7 +291,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) | |||
291 | 291 | ||
292 | do { | 292 | do { |
293 | irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); | 293 | irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); |
294 | irqnr = irqstat & ~0x1c00; | 294 | irqnr = irqstat & GICC_IAR_INT_ID_MASK; |
295 | 295 | ||
296 | if (likely(irqnr > 15 && irqnr < 1021)) { | 296 | if (likely(irqnr > 15 && irqnr < 1021)) { |
297 | irqnr = irq_find_mapping(gic->domain, irqnr); | 297 | irqnr = irq_find_mapping(gic->domain, irqnr); |
diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 7e1c91d41a87..449011b0e007 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) | |||
1208 | 1208 | ||
1209 | irq = md->ingress_irq; | 1209 | irq = md->ingress_irq; |
1210 | if (irq < 0) { | 1210 | if (irq < 0) { |
1211 | irq = create_irq(); | 1211 | irq = irq_alloc_hwirq(-1); |
1212 | if (irq < 0) { | 1212 | if (!irq) { |
1213 | netdev_err(dev, | 1213 | netdev_err(dev, |
1214 | "create_irq failed: mpipe[%d] %d\n", | 1214 | "create_irq failed: mpipe[%d] %d\n", |
1215 | instance, irq); | 1215 | instance, irq); |
@@ -1223,7 +1223,7 @@ static int tile_net_setup_interrupts(struct net_device *dev) | |||
1223 | if (rc != 0) { | 1223 | if (rc != 0) { |
1224 | netdev_err(dev, "request_irq failed: mpipe[%d] %d\n", | 1224 | netdev_err(dev, "request_irq failed: mpipe[%d] %d\n", |
1225 | instance, rc); | 1225 | instance, rc); |
1226 | destroy_irq(irq); | 1226 | irq_free_hwirq(irq); |
1227 | return rc; | 1227 | return rc; |
1228 | } | 1228 | } |
1229 | md->ingress_irq = irq; | 1229 | md->ingress_irq = irq; |
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index 6e373ea57b32..d68b030ab533 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c | |||
@@ -87,12 +87,9 @@ void unmask_ht_irq(struct irq_data *data) | |||
87 | int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) | 87 | int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) |
88 | { | 88 | { |
89 | struct ht_irq_cfg *cfg; | 89 | struct ht_irq_cfg *cfg; |
90 | int max_irq, pos, irq; | ||
90 | unsigned long flags; | 91 | unsigned long flags; |
91 | u32 data; | 92 | u32 data; |
92 | int max_irq; | ||
93 | int pos; | ||
94 | int irq; | ||
95 | int node; | ||
96 | 93 | ||
97 | pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ); | 94 | pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ); |
98 | if (!pos) | 95 | if (!pos) |
@@ -120,10 +117,8 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) | |||
120 | cfg->msg.address_lo = 0xffffffff; | 117 | cfg->msg.address_lo = 0xffffffff; |
121 | cfg->msg.address_hi = 0xffffffff; | 118 | cfg->msg.address_hi = 0xffffffff; |
122 | 119 | ||
123 | node = dev_to_node(&dev->dev); | 120 | irq = irq_alloc_hwirq(dev_to_node(&dev->dev)); |
124 | irq = create_irq_nr(0, node); | 121 | if (!irq) { |
125 | |||
126 | if (irq <= 0) { | ||
127 | kfree(cfg); | 122 | kfree(cfg); |
128 | return -EBUSY; | 123 | return -EBUSY; |
129 | } | 124 | } |
@@ -166,7 +161,7 @@ void ht_destroy_irq(unsigned int irq) | |||
166 | cfg = irq_get_handler_data(irq); | 161 | cfg = irq_get_handler_data(irq); |
167 | irq_set_chip(irq, NULL); | 162 | irq_set_chip(irq, NULL); |
168 | irq_set_handler_data(irq, NULL); | 163 | irq_set_handler_data(irq, NULL); |
169 | destroy_irq(irq); | 164 | irq_free_hwirq(irq); |
170 | 165 | ||
171 | kfree(cfg); | 166 | kfree(cfg); |
172 | } | 167 | } |
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 8f32a1323a79..81f22980b2de 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, | |||
80 | unsigned int data[2], primary; | 80 | unsigned int data[2], primary; |
81 | unsigned long flags; | 81 | unsigned long flags; |
82 | 82 | ||
83 | /* | ||
84 | * Register the IRQ position with the global IRQ map, then insert | ||
85 | * it in to the radix tree. | ||
86 | */ | ||
87 | irq_reserve_irq(irq); | ||
88 | |||
89 | raw_spin_lock_irqsave(&intc_big_lock, flags); | 83 | raw_spin_lock_irqsave(&intc_big_lock, flags); |
90 | radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq)); | 84 | radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq)); |
91 | raw_spin_unlock_irqrestore(&intc_big_lock, flags); | 85 | raw_spin_unlock_irqrestore(&intc_big_lock, flags); |
diff --git a/drivers/tty/hvc/hvc_tile.c b/drivers/tty/hvc/hvc_tile.c index af8cdaa1dcb9..147d49e95db2 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) | |||
133 | int tile_hvc_irq; | 133 | int tile_hvc_irq; |
134 | 134 | ||
135 | /* Create our IRQ and register it. */ | 135 | /* Create our IRQ and register it. */ |
136 | tile_hvc_irq = create_irq(); | 136 | tile_hvc_irq = irq_alloc_hwirq(-1); |
137 | if (tile_hvc_irq < 0) | 137 | if (!tile_hvc_irq) |
138 | return -ENXIO; | 138 | return -ENXIO; |
139 | 139 | ||
140 | tile_irq_activate(tile_hvc_irq, TILE_IRQ_PERCPU); | 140 | tile_irq_activate(tile_hvc_irq, TILE_IRQ_PERCPU); |
141 | hp = hvc_alloc(0, tile_hvc_irq, &hvc_tile_get_put_ops, 128); | 141 | hp = hvc_alloc(0, tile_hvc_irq, &hvc_tile_get_put_ops, 128); |
142 | if (IS_ERR(hp)) { | 142 | if (IS_ERR(hp)) { |
143 | destroy_irq(tile_hvc_irq); | 143 | irq_free_hwirq(tile_hvc_irq); |
144 | return PTR_ERR(hp); | 144 | return PTR_ERR(hp); |
145 | } | 145 | } |
146 | dev_set_drvdata(&pdev->dev, hp); | 146 | dev_set_drvdata(&pdev->dev, hp); |
@@ -155,7 +155,7 @@ static int hvc_tile_remove(struct platform_device *pdev) | |||
155 | 155 | ||
156 | rc = hvc_remove(hp); | 156 | rc = hvc_remove(hp); |
157 | if (rc == 0) | 157 | if (rc == 0) |
158 | destroy_irq(hp->data); | 158 | irq_free_hwirq(hp->data); |
159 | 159 | ||
160 | return rc; | 160 | return rc; |
161 | } | 161 | } |
diff --git a/drivers/tty/serial/tilegx.c b/drivers/tty/serial/tilegx.c index f92d7e6bd876..613ccf09dc2a 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) | |||
359 | } | 359 | } |
360 | 360 | ||
361 | /* Create our IRQs. */ | 361 | /* Create our IRQs. */ |
362 | port->irq = create_irq(); | 362 | port->irq = irq_alloc_hwirq(-1); |
363 | if (port->irq < 0) | 363 | if (!port->irq) |
364 | goto err_uart_dest; | 364 | goto err_uart_dest; |
365 | tile_irq_activate(port->irq, TILE_IRQ_PERCPU); | 365 | tile_irq_activate(port->irq, TILE_IRQ_PERCPU); |
366 | 366 | ||
@@ -395,7 +395,7 @@ static int tilegx_startup(struct uart_port *port) | |||
395 | err_free_irq: | 395 | err_free_irq: |
396 | free_irq(port->irq, port); | 396 | free_irq(port->irq, port); |
397 | err_dest_irq: | 397 | err_dest_irq: |
398 | destroy_irq(port->irq); | 398 | irq_free_hwirq(port->irq); |
399 | err_uart_dest: | 399 | err_uart_dest: |
400 | gxio_uart_destroy(context); | 400 | gxio_uart_destroy(context); |
401 | ret = -ENXIO; | 401 | ret = -ENXIO; |
@@ -435,7 +435,7 @@ static void tilegx_shutdown(struct uart_port *port) | |||
435 | 435 | ||
436 | if (port->irq > 0) { | 436 | if (port->irq > 0) { |
437 | free_irq(port->irq, port); | 437 | free_irq(port->irq, port); |
438 | destroy_irq(port->irq); | 438 | irq_free_hwirq(port->irq); |
439 | port->irq = 0; | 439 | port->irq = 0; |
440 | } | 440 | } |
441 | 441 | ||
diff --git a/drivers/usb/host/ehci-tilegx.c b/drivers/usb/host/ehci-tilegx.c index f3713d32c9a1..0d247673c3ca 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) | |||
142 | ehci->hcs_params = readl(&ehci->caps->hcs_params); | 142 | ehci->hcs_params = readl(&ehci->caps->hcs_params); |
143 | 143 | ||
144 | /* Create our IRQs and register them. */ | 144 | /* Create our IRQs and register them. */ |
145 | pdata->irq = create_irq(); | 145 | pdata->irq = irq_alloc_hwirq(-1); |
146 | if (pdata->irq < 0) { | 146 | if (!pdata->irq) { |
147 | ret = -ENXIO; | 147 | ret = -ENXIO; |
148 | goto err_no_irq; | 148 | goto err_no_irq; |
149 | } | 149 | } |
@@ -175,7 +175,7 @@ static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev) | |||
175 | } | 175 | } |
176 | 176 | ||
177 | err_have_irq: | 177 | err_have_irq: |
178 | destroy_irq(pdata->irq); | 178 | irq_free_hwirq(pdata->irq); |
179 | err_no_irq: | 179 | err_no_irq: |
180 | tilegx_stop_ehc(); | 180 | tilegx_stop_ehc(); |
181 | usb_put_hcd(hcd); | 181 | usb_put_hcd(hcd); |
@@ -193,7 +193,7 @@ static int ehci_hcd_tilegx_drv_remove(struct platform_device *pdev) | |||
193 | usb_put_hcd(hcd); | 193 | usb_put_hcd(hcd); |
194 | tilegx_stop_ehc(); | 194 | tilegx_stop_ehc(); |
195 | gxio_usb_host_destroy(&pdata->usb_ctx); | 195 | gxio_usb_host_destroy(&pdata->usb_ctx); |
196 | destroy_irq(pdata->irq); | 196 | irq_free_hwirq(pdata->irq); |
197 | 197 | ||
198 | return 0; | 198 | return 0; |
199 | } | 199 | } |
diff --git a/drivers/usb/host/ohci-tilegx.c b/drivers/usb/host/ohci-tilegx.c index 0b183e0b0a8a..bef6dfb0405a 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) | |||
129 | tilegx_start_ohc(); | 129 | tilegx_start_ohc(); |
130 | 130 | ||
131 | /* Create our IRQs and register them. */ | 131 | /* Create our IRQs and register them. */ |
132 | pdata->irq = create_irq(); | 132 | pdata->irq = irq_alloc_hwirq(-1); |
133 | if (pdata->irq < 0) { | 133 | if (!pdata->irq) { |
134 | ret = -ENXIO; | 134 | ret = -ENXIO; |
135 | goto err_no_irq; | 135 | goto err_no_irq; |
136 | } | 136 | } |
@@ -164,7 +164,7 @@ static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev) | |||
164 | } | 164 | } |
165 | 165 | ||
166 | err_have_irq: | 166 | err_have_irq: |
167 | destroy_irq(pdata->irq); | 167 | irq_free_hwirq(pdata->irq); |
168 | err_no_irq: | 168 | err_no_irq: |
169 | tilegx_stop_ohc(); | 169 | tilegx_stop_ohc(); |
170 | usb_put_hcd(hcd); | 170 | usb_put_hcd(hcd); |
@@ -182,7 +182,7 @@ static int ohci_hcd_tilegx_drv_remove(struct platform_device *pdev) | |||
182 | usb_put_hcd(hcd); | 182 | usb_put_hcd(hcd); |
183 | tilegx_stop_ohc(); | 183 | tilegx_stop_ohc(); |
184 | gxio_usb_host_destroy(&pdata->usb_ctx); | 184 | gxio_usb_host_destroy(&pdata->usb_ctx); |
185 | destroy_irq(pdata->irq); | 185 | irq_free_hwirq(pdata->irq); |
186 | 186 | ||
187 | return 0; | 187 | return 0; |
188 | } | 188 | } |
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index dfa12a4a0a48..c919d3d5c845 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) | |||
390 | 390 | ||
391 | static int __must_check xen_allocate_irqs_dynamic(int nvec) | 391 | static int __must_check xen_allocate_irqs_dynamic(int nvec) |
392 | { | 392 | { |
393 | int first = 0; | 393 | int i, irq = irq_alloc_descs(-1, 0, nvec, -1); |
394 | int i, irq; | ||
395 | |||
396 | #ifdef CONFIG_X86_IO_APIC | ||
397 | /* | ||
398 | * For an HVM guest or domain 0 which see "real" (emulated or | ||
399 | * actual respectively) GSIs we allocate dynamic IRQs | ||
400 | * e.g. those corresponding to event channels or MSIs | ||
401 | * etc. from the range above those "real" GSIs to avoid | ||
402 | * collisions. | ||
403 | */ | ||
404 | if (xen_initial_domain() || xen_hvm_domain()) | ||
405 | first = get_nr_irqs_gsi(); | ||
406 | #endif | ||
407 | |||
408 | irq = irq_alloc_descs_from(first, nvec, -1); | ||
409 | 394 | ||
410 | if (irq >= 0) { | 395 | if (irq >= 0) { |
411 | for (i = 0; i < nvec; i++) | 396 | for (i = 0; i < nvec; i++) |
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index cb19f09d7e3e..698ad053d064 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h | |||
@@ -199,6 +199,26 @@ extern int check_wakeup_irqs(void); | |||
199 | static inline int check_wakeup_irqs(void) { return 0; } | 199 | static inline int check_wakeup_irqs(void) { return 0; } |
200 | #endif | 200 | #endif |
201 | 201 | ||
202 | /** | ||
203 | * struct irq_affinity_notify - context for notification of IRQ affinity changes | ||
204 | * @irq: Interrupt to which notification applies | ||
205 | * @kref: Reference count, for internal use | ||
206 | * @work: Work item, for internal use | ||
207 | * @notify: Function to be called on change. This will be | ||
208 | * called in process context. | ||
209 | * @release: Function to be called on release. This will be | ||
210 | * called in process context. Once registered, the | ||
211 | * structure must only be freed when this function is | ||
212 | * called or later. | ||
213 | */ | ||
214 | struct irq_affinity_notify { | ||
215 | unsigned int irq; | ||
216 | struct kref kref; | ||
217 | struct work_struct work; | ||
218 | void (*notify)(struct irq_affinity_notify *, const cpumask_t *mask); | ||
219 | void (*release)(struct kref *ref); | ||
220 | }; | ||
221 | |||
202 | #if defined(CONFIG_SMP) | 222 | #if defined(CONFIG_SMP) |
203 | 223 | ||
204 | extern cpumask_var_t irq_default_affinity; | 224 | extern cpumask_var_t irq_default_affinity; |
@@ -242,26 +262,6 @@ extern int irq_select_affinity(unsigned int irq); | |||
242 | 262 | ||
243 | extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m); | 263 | extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m); |
244 | 264 | ||
245 | /** | ||
246 | * struct irq_affinity_notify - context for notification of IRQ affinity changes | ||
247 | * @irq: Interrupt to which notification applies | ||
248 | * @kref: Reference count, for internal use | ||
249 | * @work: Work item, for internal use | ||
250 | * @notify: Function to be called on change. This will be | ||
251 | * called in process context. | ||
252 | * @release: Function to be called on release. This will be | ||
253 | * called in process context. Once registered, the | ||
254 | * structure must only be freed when this function is | ||
255 | * called or later. | ||
256 | */ | ||
257 | struct irq_affinity_notify { | ||
258 | unsigned int irq; | ||
259 | struct kref kref; | ||
260 | struct work_struct work; | ||
261 | void (*notify)(struct irq_affinity_notify *, const cpumask_t *mask); | ||
262 | void (*release)(struct kref *ref); | ||
263 | }; | ||
264 | |||
265 | extern int | 265 | extern int |
266 | irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); | 266 | irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); |
267 | 267 | ||
@@ -289,6 +289,12 @@ static inline int irq_set_affinity_hint(unsigned int irq, | |||
289 | { | 289 | { |
290 | return -EINVAL; | 290 | return -EINVAL; |
291 | } | 291 | } |
292 | |||
293 | static inline int | ||
294 | irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify) | ||
295 | { | ||
296 | return 0; | ||
297 | } | ||
292 | #endif /* CONFIG_SMP */ | 298 | #endif /* CONFIG_SMP */ |
293 | 299 | ||
294 | /* | 300 | /* |
diff --git a/include/linux/irq.h b/include/linux/irq.h index 5c57efb863d0..0d998d8b01d8 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
@@ -525,24 +525,6 @@ static inline void irq_set_percpu_devid_flags(unsigned int irq) | |||
525 | IRQ_NOPROBE | IRQ_PER_CPU_DEVID); | 525 | IRQ_NOPROBE | IRQ_PER_CPU_DEVID); |
526 | } | 526 | } |
527 | 527 | ||
528 | /* Handle dynamic irq creation and destruction */ | ||
529 | extern unsigned int create_irq_nr(unsigned int irq_want, int node); | ||
530 | extern unsigned int __create_irqs(unsigned int from, unsigned int count, | ||
531 | int node); | ||
532 | extern int create_irq(void); | ||
533 | extern void destroy_irq(unsigned int irq); | ||
534 | extern void destroy_irqs(unsigned int irq, unsigned int count); | ||
535 | |||
536 | /* | ||
537 | * Dynamic irq helper functions. Obsolete. Use irq_alloc_desc* and | ||
538 | * irq_free_desc instead. | ||
539 | */ | ||
540 | extern void dynamic_irq_cleanup(unsigned int irq); | ||
541 | static inline void dynamic_irq_init(unsigned int irq) | ||
542 | { | ||
543 | dynamic_irq_cleanup(irq); | ||
544 | } | ||
545 | |||
546 | /* Set/get chip/data for an IRQ: */ | 528 | /* Set/get chip/data for an IRQ: */ |
547 | extern int irq_set_chip(unsigned int irq, struct irq_chip *chip); | 529 | extern int irq_set_chip(unsigned int irq, struct irq_chip *chip); |
548 | extern int irq_set_handler_data(unsigned int irq, void *data); | 530 | extern int irq_set_handler_data(unsigned int irq, void *data); |
@@ -625,17 +607,29 @@ int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, | |||
625 | irq_alloc_descs(-1, from, cnt, node) | 607 | irq_alloc_descs(-1, from, cnt, node) |
626 | 608 | ||
627 | void irq_free_descs(unsigned int irq, unsigned int cnt); | 609 | void irq_free_descs(unsigned int irq, unsigned int cnt); |
628 | int irq_reserve_irqs(unsigned int from, unsigned int cnt); | ||
629 | |||
630 | static inline void irq_free_desc(unsigned int irq) | 610 | static inline void irq_free_desc(unsigned int irq) |
631 | { | 611 | { |
632 | irq_free_descs(irq, 1); | 612 | irq_free_descs(irq, 1); |
633 | } | 613 | } |
634 | 614 | ||
635 | static inline int irq_reserve_irq(unsigned int irq) | 615 | #ifdef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ |
616 | unsigned int irq_alloc_hwirqs(int cnt, int node); | ||
617 | static inline unsigned int irq_alloc_hwirq(int node) | ||
618 | { | ||
619 | return irq_alloc_hwirqs(1, node); | ||
620 | } | ||
621 | void irq_free_hwirqs(unsigned int from, int cnt); | ||
622 | static inline void irq_free_hwirq(unsigned int irq) | ||
636 | { | 623 | { |
637 | return irq_reserve_irqs(irq, 1); | 624 | return irq_free_hwirqs(irq, 1); |
638 | } | 625 | } |
626 | int arch_setup_hwirq(unsigned int irq, int node); | ||
627 | void arch_teardown_hwirq(unsigned int irq); | ||
628 | #endif | ||
629 | |||
630 | #ifdef CONFIG_GENERIC_IRQ_LEGACY | ||
631 | void irq_init_desc(unsigned int irq); | ||
632 | #endif | ||
639 | 633 | ||
640 | #ifndef irq_reg_writel | 634 | #ifndef irq_reg_writel |
641 | # define irq_reg_writel(val, addr) writel(val, addr) | 635 | # define irq_reg_writel(val, addr) writel(val, addr) |
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 7ed92d0560d5..45e2d8c15bd2 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h | |||
@@ -21,6 +21,8 @@ | |||
21 | #define GIC_CPU_ACTIVEPRIO 0xd0 | 21 | #define GIC_CPU_ACTIVEPRIO 0xd0 |
22 | #define GIC_CPU_IDENT 0xfc | 22 | #define GIC_CPU_IDENT 0xfc |
23 | 23 | ||
24 | #define GICC_IAR_INT_ID_MASK 0x3ff | ||
25 | |||
24 | #define GIC_DIST_CTRL 0x000 | 26 | #define GIC_DIST_CTRL 0x000 |
25 | #define GIC_DIST_CTR 0x004 | 27 | #define GIC_DIST_CTR 0x004 |
26 | #define GIC_DIST_IGROUP 0x080 | 28 | #define GIC_DIST_IGROUP 0x080 |
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 26e2661d3935..472c021a2d4f 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h | |||
@@ -27,6 +27,8 @@ struct irq_desc; | |||
27 | * @irq_count: stats field to detect stalled irqs | 27 | * @irq_count: stats field to detect stalled irqs |
28 | * @last_unhandled: aging timer for unhandled count | 28 | * @last_unhandled: aging timer for unhandled count |
29 | * @irqs_unhandled: stats field for spurious unhandled interrupts | 29 | * @irqs_unhandled: stats field for spurious unhandled interrupts |
30 | * @threads_handled: stats field for deferred spurious detection of threaded handlers | ||
31 | * @threads_handled_last: comparator field for deferred spurious detection of theraded handlers | ||
30 | * @lock: locking for SMP | 32 | * @lock: locking for SMP |
31 | * @affinity_hint: hint to user space for preferred irq affinity | 33 | * @affinity_hint: hint to user space for preferred irq affinity |
32 | * @affinity_notify: context for notification of affinity changes | 34 | * @affinity_notify: context for notification of affinity changes |
@@ -52,6 +54,8 @@ struct irq_desc { | |||
52 | unsigned int irq_count; /* For detecting broken IRQs */ | 54 | unsigned int irq_count; /* For detecting broken IRQs */ |
53 | unsigned long last_unhandled; /* Aging timer for unhandled count */ | 55 | unsigned long last_unhandled; /* Aging timer for unhandled count */ |
54 | unsigned int irqs_unhandled; | 56 | unsigned int irqs_unhandled; |
57 | atomic_t threads_handled; | ||
58 | int threads_handled_last; | ||
55 | raw_spinlock_t lock; | 59 | raw_spinlock_t lock; |
56 | struct cpumask *percpu_enabled; | 60 | struct cpumask *percpu_enabled; |
57 | #ifdef CONFIG_SMP | 61 | #ifdef CONFIG_SMP |
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index 07cbdfea9ae2..d269cecdfbf0 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig | |||
@@ -5,6 +5,10 @@ menu "IRQ subsystem" | |||
5 | config MAY_HAVE_SPARSE_IRQ | 5 | config MAY_HAVE_SPARSE_IRQ |
6 | bool | 6 | bool |
7 | 7 | ||
8 | # Legacy support, required for itanic | ||
9 | config GENERIC_IRQ_LEGACY | ||
10 | bool | ||
11 | |||
8 | # Enable the generic irq autoprobe mechanism | 12 | # Enable the generic irq autoprobe mechanism |
9 | config GENERIC_IRQ_PROBE | 13 | config GENERIC_IRQ_PROBE |
10 | bool | 14 | bool |
@@ -17,6 +21,11 @@ config GENERIC_IRQ_SHOW | |||
17 | config GENERIC_IRQ_SHOW_LEVEL | 21 | config GENERIC_IRQ_SHOW_LEVEL |
18 | bool | 22 | bool |
19 | 23 | ||
24 | # Facility to allocate a hardware interrupt. This is legacy support | ||
25 | # and should not be used in new code. Use irq domains instead. | ||
26 | config GENERIC_IRQ_LEGACY_ALLOC_HWIRQ | ||
27 | bool | ||
28 | |||
20 | # Support for delayed migration from interrupt context | 29 | # Support for delayed migration from interrupt context |
21 | config GENERIC_PENDING_IRQ | 30 | config GENERIC_PENDING_IRQ |
22 | bool | 31 | bool |
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 6397df2d6945..a2b28a2fd7b1 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) | |||
40 | irq_put_desc_unlock(desc, flags); | 40 | irq_put_desc_unlock(desc, flags); |
41 | /* | 41 | /* |
42 | * For !CONFIG_SPARSE_IRQ make the irq show up in | 42 | * For !CONFIG_SPARSE_IRQ make the irq show up in |
43 | * allocated_irqs. For the CONFIG_SPARSE_IRQ case, it is | 43 | * allocated_irqs. |
44 | * already marked, and this call is harmless. | ||
45 | */ | 44 | */ |
46 | irq_reserve_irq(irq); | 45 | irq_mark_irq(irq); |
47 | return 0; | 46 | return 0; |
48 | } | 47 | } |
49 | EXPORT_SYMBOL(irq_set_chip); | 48 | EXPORT_SYMBOL(irq_set_chip); |
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index ddf1ffeb79f1..099ea2e0eb88 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
@@ -33,7 +33,7 @@ enum { | |||
33 | }; | 33 | }; |
34 | 34 | ||
35 | /* | 35 | /* |
36 | * Bit masks for desc->state | 36 | * Bit masks for desc->core_internal_state__do_not_mess_with_it |
37 | * | 37 | * |
38 | * IRQS_AUTODETECT - autodetection in progress | 38 | * IRQS_AUTODETECT - autodetection in progress |
39 | * IRQS_SPURIOUS_DISABLED - was disabled due to spurious interrupt | 39 | * IRQS_SPURIOUS_DISABLED - was disabled due to spurious interrupt |
@@ -76,6 +76,12 @@ extern void mask_irq(struct irq_desc *desc); | |||
76 | extern void unmask_irq(struct irq_desc *desc); | 76 | extern void unmask_irq(struct irq_desc *desc); |
77 | extern void unmask_threaded_irq(struct irq_desc *desc); | 77 | extern void unmask_threaded_irq(struct irq_desc *desc); |
78 | 78 | ||
79 | #ifdef CONFIG_SPARSE_IRQ | ||
80 | static inline void irq_mark_irq(unsigned int irq) { } | ||
81 | #else | ||
82 | extern void irq_mark_irq(unsigned int irq); | ||
83 | #endif | ||
84 | |||
79 | extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); | 85 | extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); |
80 | 86 | ||
81 | irqreturn_t handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action); | 87 | 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 bb07f2928f4b..7339e42a85ab 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c | |||
@@ -278,7 +278,12 @@ EXPORT_SYMBOL(irq_to_desc); | |||
278 | 278 | ||
279 | static void free_desc(unsigned int irq) | 279 | static void free_desc(unsigned int irq) |
280 | { | 280 | { |
281 | dynamic_irq_cleanup(irq); | 281 | struct irq_desc *desc = irq_to_desc(irq); |
282 | unsigned long flags; | ||
283 | |||
284 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
285 | desc_set_defaults(irq, desc, desc_node(desc), NULL); | ||
286 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
282 | } | 287 | } |
283 | 288 | ||
284 | static inline int alloc_descs(unsigned int start, unsigned int cnt, int node, | 289 | static inline int alloc_descs(unsigned int start, unsigned int cnt, int node, |
@@ -299,6 +304,20 @@ static int irq_expand_nr_irqs(unsigned int nr) | |||
299 | return -ENOMEM; | 304 | return -ENOMEM; |
300 | } | 305 | } |
301 | 306 | ||
307 | void irq_mark_irq(unsigned int irq) | ||
308 | { | ||
309 | mutex_lock(&sparse_irq_lock); | ||
310 | bitmap_set(allocated_irqs, irq, 1); | ||
311 | mutex_unlock(&sparse_irq_lock); | ||
312 | } | ||
313 | |||
314 | #ifdef CONFIG_GENERIC_IRQ_LEGACY | ||
315 | void irq_init_desc(unsigned int irq) | ||
316 | { | ||
317 | free_desc(irq); | ||
318 | } | ||
319 | #endif | ||
320 | |||
302 | #endif /* !CONFIG_SPARSE_IRQ */ | 321 | #endif /* !CONFIG_SPARSE_IRQ */ |
303 | 322 | ||
304 | /** | 323 | /** |
@@ -396,30 +415,56 @@ err: | |||
396 | } | 415 | } |
397 | EXPORT_SYMBOL_GPL(__irq_alloc_descs); | 416 | EXPORT_SYMBOL_GPL(__irq_alloc_descs); |
398 | 417 | ||
418 | #ifdef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ | ||
399 | /** | 419 | /** |
400 | * irq_reserve_irqs - mark irqs allocated | 420 | * irq_alloc_hwirqs - Allocate an irq descriptor and initialize the hardware |
401 | * @from: mark from irq number | 421 | * @cnt: number of interrupts to allocate |
402 | * @cnt: number of irqs to mark | 422 | * @node: node on which to allocate |
403 | * | 423 | * |
404 | * Returns 0 on success or an appropriate error code | 424 | * Returns an interrupt number > 0 or 0, if the allocation fails. |
405 | */ | 425 | */ |
406 | int irq_reserve_irqs(unsigned int from, unsigned int cnt) | 426 | unsigned int irq_alloc_hwirqs(int cnt, int node) |
407 | { | 427 | { |
408 | unsigned int start; | 428 | int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL); |
409 | int ret = 0; | ||
410 | 429 | ||
411 | if (!cnt || (from + cnt) > nr_irqs) | 430 | if (irq < 0) |
412 | return -EINVAL; | 431 | return 0; |
413 | 432 | ||
414 | mutex_lock(&sparse_irq_lock); | 433 | for (i = irq; cnt > 0; i++, cnt--) { |
415 | start = bitmap_find_next_zero_area(allocated_irqs, nr_irqs, from, cnt, 0); | 434 | if (arch_setup_hwirq(i, node)) |
416 | if (start == from) | 435 | goto err; |
417 | bitmap_set(allocated_irqs, start, cnt); | 436 | irq_clear_status_flags(i, _IRQ_NOREQUEST); |
418 | else | 437 | } |
419 | ret = -EEXIST; | 438 | return irq; |
420 | mutex_unlock(&sparse_irq_lock); | 439 | |
421 | return ret; | 440 | err: |
441 | for (i--; i >= irq; i--) { | ||
442 | irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE); | ||
443 | arch_teardown_hwirq(i); | ||
444 | } | ||
445 | irq_free_descs(irq, cnt); | ||
446 | return 0; | ||
447 | } | ||
448 | EXPORT_SYMBOL_GPL(irq_alloc_hwirqs); | ||
449 | |||
450 | /** | ||
451 | * irq_free_hwirqs - Free irq descriptor and cleanup the hardware | ||
452 | * @from: Free from irq number | ||
453 | * @cnt: number of interrupts to free | ||
454 | * | ||
455 | */ | ||
456 | void irq_free_hwirqs(unsigned int from, int cnt) | ||
457 | { | ||
458 | int i; | ||
459 | |||
460 | for (i = from; cnt > 0; i++, cnt--) { | ||
461 | irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE); | ||
462 | arch_teardown_hwirq(i); | ||
463 | } | ||
464 | irq_free_descs(from, cnt); | ||
422 | } | 465 | } |
466 | EXPORT_SYMBOL_GPL(irq_free_hwirqs); | ||
467 | #endif | ||
423 | 468 | ||
424 | /** | 469 | /** |
425 | * irq_get_next_irq - get next allocated irq number | 470 | * irq_get_next_irq - get next allocated irq number |
@@ -482,20 +527,6 @@ int irq_set_percpu_devid(unsigned int irq) | |||
482 | return 0; | 527 | return 0; |
483 | } | 528 | } |
484 | 529 | ||
485 | /** | ||
486 | * dynamic_irq_cleanup - cleanup a dynamically allocated irq | ||
487 | * @irq: irq number to initialize | ||
488 | */ | ||
489 | void dynamic_irq_cleanup(unsigned int irq) | ||
490 | { | ||
491 | struct irq_desc *desc = irq_to_desc(irq); | ||
492 | unsigned long flags; | ||
493 | |||
494 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
495 | desc_set_defaults(irq, desc, desc_node(desc), NULL); | ||
496 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
497 | } | ||
498 | |||
499 | void kstat_incr_irq_this_cpu(unsigned int irq) | 530 | void kstat_incr_irq_this_cpu(unsigned int irq) |
500 | { | 531 | { |
501 | kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq)); | 532 | kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq)); |
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index f14033700c25..eb5e10e32e05 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c | |||
@@ -27,14 +27,14 @@ static struct irq_domain *irq_default_domain; | |||
27 | * __irq_domain_add() - Allocate a new irq_domain data structure | 27 | * __irq_domain_add() - Allocate a new irq_domain data structure |
28 | * @of_node: optional device-tree node of the interrupt controller | 28 | * @of_node: optional device-tree node of the interrupt controller |
29 | * @size: Size of linear map; 0 for radix mapping only | 29 | * @size: Size of linear map; 0 for radix mapping only |
30 | * @hwirq_max: Maximum number of interrupts supported by controller | ||
30 | * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no | 31 | * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no |
31 | * direct mapping | 32 | * direct mapping |
32 | * @ops: map/unmap domain callbacks | 33 | * @ops: map/unmap domain callbacks |
33 | * @host_data: Controller private data pointer | 34 | * @host_data: Controller private data pointer |
34 | * | 35 | * |
35 | * Allocates and initialize and irq_domain structure. Caller is expected to | 36 | * Allocates and initialize and irq_domain structure. |
36 | * register allocated irq_domain with irq_domain_register(). Returns pointer | 37 | * Returns pointer to IRQ domain, or NULL on failure. |
37 | * to IRQ domain, or NULL on failure. | ||
38 | */ | 38 | */ |
39 | struct irq_domain *__irq_domain_add(struct device_node *of_node, int size, | 39 | struct irq_domain *__irq_domain_add(struct device_node *of_node, int size, |
40 | irq_hw_number_t hwirq_max, int direct_max, | 40 | irq_hw_number_t hwirq_max, int direct_max, |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index d34131ca372b..3dc6a61bf06a 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -886,8 +886,8 @@ static int irq_thread(void *data) | |||
886 | irq_thread_check_affinity(desc, action); | 886 | irq_thread_check_affinity(desc, action); |
887 | 887 | ||
888 | action_ret = handler_fn(desc, action); | 888 | action_ret = handler_fn(desc, action); |
889 | if (!noirqdebug) | 889 | if (action_ret == IRQ_HANDLED) |
890 | note_interrupt(action->irq, desc, action_ret); | 890 | atomic_inc(&desc->threads_handled); |
891 | 891 | ||
892 | wake_threads_waitq(desc); | 892 | wake_threads_waitq(desc); |
893 | } | 893 | } |
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index a1d8cc63b56e..e2514b0e439e 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, | |||
270 | return action && (action->flags & IRQF_IRQPOLL); | 270 | return action && (action->flags & IRQF_IRQPOLL); |
271 | } | 271 | } |
272 | 272 | ||
273 | #define SPURIOUS_DEFERRED 0x80000000 | ||
274 | |||
273 | void note_interrupt(unsigned int irq, struct irq_desc *desc, | 275 | void note_interrupt(unsigned int irq, struct irq_desc *desc, |
274 | irqreturn_t action_ret) | 276 | irqreturn_t action_ret) |
275 | { | 277 | { |
@@ -277,15 +279,111 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc, | |||
277 | irq_settings_is_polled(desc)) | 279 | irq_settings_is_polled(desc)) |
278 | return; | 280 | return; |
279 | 281 | ||
280 | /* we get here again via the threaded handler */ | ||
281 | if (action_ret == IRQ_WAKE_THREAD) | ||
282 | return; | ||
283 | |||
284 | if (bad_action_ret(action_ret)) { | 282 | if (bad_action_ret(action_ret)) { |
285 | report_bad_irq(irq, desc, action_ret); | 283 | report_bad_irq(irq, desc, action_ret); |
286 | return; | 284 | return; |
287 | } | 285 | } |
288 | 286 | ||
287 | /* | ||
288 | * We cannot call note_interrupt from the threaded handler | ||
289 | * because we need to look at the compound of all handlers | ||
290 | * (primary and threaded). Aside of that in the threaded | ||
291 | * shared case we have no serialization against an incoming | ||
292 | * hardware interrupt while we are dealing with a threaded | ||
293 | * result. | ||
294 | * | ||
295 | * So in case a thread is woken, we just note the fact and | ||
296 | * defer the analysis to the next hardware interrupt. | ||
297 | * | ||
298 | * The threaded handlers store whether they sucessfully | ||
299 | * handled an interrupt and we check whether that number | ||
300 | * changed versus the last invocation. | ||
301 | * | ||
302 | * We could handle all interrupts with the delayed by one | ||
303 | * mechanism, but for the non forced threaded case we'd just | ||
304 | * add pointless overhead to the straight hardirq interrupts | ||
305 | * for the sake of a few lines less code. | ||
306 | */ | ||
307 | if (action_ret & IRQ_WAKE_THREAD) { | ||
308 | /* | ||
309 | * There is a thread woken. Check whether one of the | ||
310 | * shared primary handlers returned IRQ_HANDLED. If | ||
311 | * not we defer the spurious detection to the next | ||
312 | * interrupt. | ||
313 | */ | ||
314 | if (action_ret == IRQ_WAKE_THREAD) { | ||
315 | int handled; | ||
316 | /* | ||
317 | * We use bit 31 of thread_handled_last to | ||
318 | * denote the deferred spurious detection | ||
319 | * active. No locking necessary as | ||
320 | * thread_handled_last is only accessed here | ||
321 | * and we have the guarantee that hard | ||
322 | * interrupts are not reentrant. | ||
323 | */ | ||
324 | if (!(desc->threads_handled_last & SPURIOUS_DEFERRED)) { | ||
325 | desc->threads_handled_last |= SPURIOUS_DEFERRED; | ||
326 | return; | ||
327 | } | ||
328 | /* | ||
329 | * Check whether one of the threaded handlers | ||
330 | * returned IRQ_HANDLED since the last | ||
331 | * interrupt happened. | ||
332 | * | ||
333 | * For simplicity we just set bit 31, as it is | ||
334 | * set in threads_handled_last as well. So we | ||
335 | * avoid extra masking. And we really do not | ||
336 | * care about the high bits of the handled | ||
337 | * count. We just care about the count being | ||
338 | * different than the one we saw before. | ||
339 | */ | ||
340 | handled = atomic_read(&desc->threads_handled); | ||
341 | handled |= SPURIOUS_DEFERRED; | ||
342 | if (handled != desc->threads_handled_last) { | ||
343 | action_ret = IRQ_HANDLED; | ||
344 | /* | ||
345 | * Note: We keep the SPURIOUS_DEFERRED | ||
346 | * bit set. We are handling the | ||
347 | * previous invocation right now. | ||
348 | * Keep it for the current one, so the | ||
349 | * next hardware interrupt will | ||
350 | * account for it. | ||
351 | */ | ||
352 | desc->threads_handled_last = handled; | ||
353 | } else { | ||
354 | /* | ||
355 | * None of the threaded handlers felt | ||
356 | * responsible for the last interrupt | ||
357 | * | ||
358 | * We keep the SPURIOUS_DEFERRED bit | ||
359 | * set in threads_handled_last as we | ||
360 | * need to account for the current | ||
361 | * interrupt as well. | ||
362 | */ | ||
363 | action_ret = IRQ_NONE; | ||
364 | } | ||
365 | } else { | ||
366 | /* | ||
367 | * One of the primary handlers returned | ||
368 | * IRQ_HANDLED. So we don't care about the | ||
369 | * threaded handlers on the same line. Clear | ||
370 | * the deferred detection bit. | ||
371 | * | ||
372 | * In theory we could/should check whether the | ||
373 | * deferred bit is set and take the result of | ||
374 | * the previous run into account here as | ||
375 | * well. But it's really not worth the | ||
376 | * trouble. If every other interrupt is | ||
377 | * handled we never trigger the spurious | ||
378 | * detector. And if this is just the one out | ||
379 | * of 100k unhandled ones which is handled | ||
380 | * then we merily delay the spurious detection | ||
381 | * by one hard interrupt. Not a real problem. | ||
382 | */ | ||
383 | desc->threads_handled_last &= ~SPURIOUS_DEFERRED; | ||
384 | } | ||
385 | } | ||
386 | |||
289 | if (unlikely(action_ret == IRQ_NONE)) { | 387 | if (unlikely(action_ret == IRQ_NONE)) { |
290 | /* | 388 | /* |
291 | * If we are seeing only the odd spurious IRQ caused by | 389 | * If we are seeing only the odd spurious IRQ caused by |