diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 13:27:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 13:27:19 -0400 |
commit | c207f3a43194e108dda43dc9a1ce507335cff6b9 (patch) | |
tree | 55880f8301e8546b1908f69947d0d41aaa044814 /arch/microblaze | |
parent | c7c66c0cb0c77b1a8edf09bca57d922312d58030 (diff) | |
parent | e7cc3aca0f6a36b018934264ee20bee45dc13e29 (diff) |
Merge tag 'irqdomain-for-linus' of git://git.secretlab.ca/git/linux-2.6
Pull irq_domain support for all architectures from Grant Likely:
"Generialize powerpc's irq_host as irq_domain
This branch takes the PowerPC irq_host infrastructure (reverse mapping
from Linux IRQ numbers to hardware irq numbering), generalizes it,
renames it to irq_domain, and makes it available to all architectures.
Originally the plan has been to create an all-new irq_domain
implementation which addresses some of the powerpc shortcomings such
as not handling 1:1 mappings well, but doing that proved to be far
more difficult and invasive than generalizing the working code and
refactoring it in-place. So, this branch rips out the 'new'
irq_domain and replaces it with the modified powerpc version (in a
fully bisectable way of course). It converts all users over to the
new API and makes irq_domain selectable on any architecture.
No architecture is forced to enable irq_domain, but the infrastructure
is required for doing OpenFirmware style irq translations. It will
even work on SPARC even though SPARC has it's own mechanism for
translating irqs at boot time. MIPS, microblaze, embedded x86 and c6x
are converted too.
The resulting irq_domain code is probably still too verbose and can be
optimized more, but that can be done incrementally and is a task for
follow-on patches."
* tag 'irqdomain-for-linus' of git://git.secretlab.ca/git/linux-2.6: (31 commits)
dt: fix twl4030 for non-dt compile on x86
mfd: twl-core: Add IRQ_DOMAIN dependency
devicetree: Add empty of_platform_populate() for !CONFIG_OF_ADDRESS (sparc)
irq_domain: Centralize definition of irq_dispose_mapping()
irq_domain/mips: Allow irq_domain on MIPS
irq_domain/x86: Convert x86 (embedded) to use common irq_domain
ppc-6xx: fix build failure in flipper-pic.c and hlwd-pic.c
irq_domain/microblaze: Convert microblaze to use irq_domains
irq_domain/powerpc: Replace custom xlate functions with library functions
irq_domain/powerpc: constify irq_domain_ops
irq_domain/c6x: Use library of xlate functions
irq_domain/c6x: constify irq_domain structures
irq_domain/c6x: Convert c6x to use generic irq_domain support.
irq_domain: constify irq_domain_ops
irq_domain: Create common xlate functions that device drivers can use
irq_domain: Remove irq_domain_add_simple()
irq_domain: Remove 'new' irq_domain in favour of the ppc one
mfd: twl-core.c: Fix the number of interrupts managed by twl4030
of/address: add empty static inlines for !CONFIG_OF
irq_domain: Add support for base irq and hwirq in legacy mappings
...
Diffstat (limited to 'arch/microblaze')
-rw-r--r-- | arch/microblaze/Kconfig | 1 | ||||
-rw-r--r-- | arch/microblaze/include/asm/hardirq.h | 16 | ||||
-rw-r--r-- | arch/microblaze/include/asm/irq.h | 42 | ||||
-rw-r--r-- | arch/microblaze/kernel/intc.c | 61 | ||||
-rw-r--r-- | arch/microblaze/kernel/irq.c | 24 | ||||
-rw-r--r-- | arch/microblaze/kernel/setup.c | 2 |
6 files changed, 45 insertions, 101 deletions
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index c8d6efb99dbf..11060fa87da3 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig | |||
@@ -14,6 +14,7 @@ config MICROBLAZE | |||
14 | select TRACING_SUPPORT | 14 | select TRACING_SUPPORT |
15 | select OF | 15 | select OF |
16 | select OF_EARLY_FLATTREE | 16 | select OF_EARLY_FLATTREE |
17 | select IRQ_DOMAIN | ||
17 | select HAVE_GENERIC_HARDIRQS | 18 | select HAVE_GENERIC_HARDIRQS |
18 | select GENERIC_IRQ_PROBE | 19 | select GENERIC_IRQ_PROBE |
19 | select GENERIC_IRQ_SHOW | 20 | select GENERIC_IRQ_SHOW |
diff --git a/arch/microblaze/include/asm/hardirq.h b/arch/microblaze/include/asm/hardirq.h index cd1ac9aad56c..fb3c05a0cbbf 100644 --- a/arch/microblaze/include/asm/hardirq.h +++ b/arch/microblaze/include/asm/hardirq.h | |||
@@ -1,17 +1 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 Atmark Techno, Inc. | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | */ | ||
8 | |||
9 | #ifndef _ASM_MICROBLAZE_HARDIRQ_H | ||
10 | #define _ASM_MICROBLAZE_HARDIRQ_H | ||
11 | |||
12 | /* should be defined in each interrupt controller driver */ | ||
13 | extern unsigned int get_irq(struct pt_regs *regs); | ||
14 | |||
15 | #include <asm-generic/hardirq.h> | #include <asm-generic/hardirq.h> | |
16 | |||
17 | #endif /* _ASM_MICROBLAZE_HARDIRQ_H */ | ||
diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h index a175132e4496..bab3b1393ad4 100644 --- a/arch/microblaze/include/asm/irq.h +++ b/arch/microblaze/include/asm/irq.h | |||
@@ -9,49 +9,13 @@ | |||
9 | #ifndef _ASM_MICROBLAZE_IRQ_H | 9 | #ifndef _ASM_MICROBLAZE_IRQ_H |
10 | #define _ASM_MICROBLAZE_IRQ_H | 10 | #define _ASM_MICROBLAZE_IRQ_H |
11 | 11 | ||
12 | 12 | #define NR_IRQS (32 + 1) | |
13 | /* | ||
14 | * Linux IRQ# is currently offset by one to map to the hardware | ||
15 | * irq number. So hardware IRQ0 maps to Linux irq 1. | ||
16 | */ | ||
17 | #define NO_IRQ_OFFSET 1 | ||
18 | #define IRQ_OFFSET NO_IRQ_OFFSET | ||
19 | #define NR_IRQS (32 + IRQ_OFFSET) | ||
20 | #include <asm-generic/irq.h> | 13 | #include <asm-generic/irq.h> |
21 | 14 | ||
22 | /* This type is the placeholder for a hardware interrupt number. It has to | ||
23 | * be big enough to enclose whatever representation is used by a given | ||
24 | * platform. | ||
25 | */ | ||
26 | typedef unsigned long irq_hw_number_t; | ||
27 | |||
28 | extern unsigned int nr_irq; | ||
29 | |||
30 | struct pt_regs; | 15 | struct pt_regs; |
31 | extern void do_IRQ(struct pt_regs *regs); | 16 | extern void do_IRQ(struct pt_regs *regs); |
32 | 17 | ||
33 | /** FIXME - not implement | 18 | /* should be defined in each interrupt controller driver */ |
34 | * irq_dispose_mapping - Unmap an interrupt | 19 | extern unsigned int get_irq(void); |
35 | * @virq: linux virq number of the interrupt to unmap | ||
36 | */ | ||
37 | static inline void irq_dispose_mapping(unsigned int virq) | ||
38 | { | ||
39 | return; | ||
40 | } | ||
41 | |||
42 | struct irq_host; | ||
43 | |||
44 | /** | ||
45 | * irq_create_mapping - Map a hardware interrupt into linux virq space | ||
46 | * @host: host owning this hardware interrupt or NULL for default host | ||
47 | * @hwirq: hardware irq number in that host space | ||
48 | * | ||
49 | * Only one mapping per hardware interrupt is permitted. Returns a linux | ||
50 | * virq number. | ||
51 | * If the sense/trigger is to be specified, set_irq_type() should be called | ||
52 | * on the number returned from that call. | ||
53 | */ | ||
54 | extern unsigned int irq_create_mapping(struct irq_host *host, | ||
55 | irq_hw_number_t hwirq); | ||
56 | 20 | ||
57 | #endif /* _ASM_MICROBLAZE_IRQ_H */ | 21 | #endif /* _ASM_MICROBLAZE_IRQ_H */ |
diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c index 44b177e2ab12..ad120672cee5 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c | |||
@@ -9,6 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/irqdomain.h> | ||
12 | #include <linux/irq.h> | 13 | #include <linux/irq.h> |
13 | #include <asm/page.h> | 14 | #include <asm/page.h> |
14 | #include <linux/io.h> | 15 | #include <linux/io.h> |
@@ -25,8 +26,6 @@ static unsigned int intc_baseaddr; | |||
25 | #define INTC_BASE intc_baseaddr | 26 | #define INTC_BASE intc_baseaddr |
26 | #endif | 27 | #endif |
27 | 28 | ||
28 | unsigned int nr_irq; | ||
29 | |||
30 | /* No one else should require these constants, so define them locally here. */ | 29 | /* No one else should require these constants, so define them locally here. */ |
31 | #define ISR 0x00 /* Interrupt Status Register */ | 30 | #define ISR 0x00 /* Interrupt Status Register */ |
32 | #define IPR 0x04 /* Interrupt Pending Register */ | 31 | #define IPR 0x04 /* Interrupt Pending Register */ |
@@ -84,24 +83,45 @@ static struct irq_chip intc_dev = { | |||
84 | .irq_mask_ack = intc_mask_ack, | 83 | .irq_mask_ack = intc_mask_ack, |
85 | }; | 84 | }; |
86 | 85 | ||
87 | unsigned int get_irq(struct pt_regs *regs) | 86 | static struct irq_domain *root_domain; |
87 | |||
88 | unsigned int get_irq(void) | ||
88 | { | 89 | { |
89 | int irq; | 90 | unsigned int hwirq, irq = -1; |
90 | 91 | ||
91 | /* | 92 | hwirq = in_be32(INTC_BASE + IVR); |
92 | * NOTE: This function is the one that needs to be improved in | 93 | if (hwirq != -1U) |
93 | * order to handle multiple interrupt controllers. It currently | 94 | irq = irq_find_mapping(root_domain, hwirq); |
94 | * is hardcoded to check for interrupts only on the first INTC. | 95 | |
95 | */ | 96 | pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq); |
96 | irq = in_be32(INTC_BASE + IVR) + NO_IRQ_OFFSET; | ||
97 | pr_debug("get_irq: %d\n", irq); | ||
98 | 97 | ||
99 | return irq; | 98 | return irq; |
100 | } | 99 | } |
101 | 100 | ||
101 | int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) | ||
102 | { | ||
103 | u32 intr_mask = (u32)d->host_data; | ||
104 | |||
105 | if (intr_mask & (1 << hw)) { | ||
106 | irq_set_chip_and_handler_name(irq, &intc_dev, | ||
107 | handle_edge_irq, "edge"); | ||
108 | irq_clear_status_flags(irq, IRQ_LEVEL); | ||
109 | } else { | ||
110 | irq_set_chip_and_handler_name(irq, &intc_dev, | ||
111 | handle_level_irq, "level"); | ||
112 | irq_set_status_flags(irq, IRQ_LEVEL); | ||
113 | } | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static const struct irq_domain_ops xintc_irq_domain_ops = { | ||
118 | .xlate = irq_domain_xlate_onetwocell, | ||
119 | .map = xintc_map, | ||
120 | }; | ||
121 | |||
102 | void __init init_IRQ(void) | 122 | void __init init_IRQ(void) |
103 | { | 123 | { |
104 | u32 i, intr_mask; | 124 | u32 nr_irq, intr_mask; |
105 | struct device_node *intc = NULL; | 125 | struct device_node *intc = NULL; |
106 | #ifdef CONFIG_SELFMOD_INTC | 126 | #ifdef CONFIG_SELFMOD_INTC |
107 | unsigned int intc_baseaddr = 0; | 127 | unsigned int intc_baseaddr = 0; |
@@ -146,16 +166,9 @@ void __init init_IRQ(void) | |||
146 | /* Turn on the Master Enable. */ | 166 | /* Turn on the Master Enable. */ |
147 | out_be32(intc_baseaddr + MER, MER_HIE | MER_ME); | 167 | out_be32(intc_baseaddr + MER, MER_HIE | MER_ME); |
148 | 168 | ||
149 | for (i = IRQ_OFFSET; i < (nr_irq + IRQ_OFFSET); ++i) { | 169 | /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm |
150 | if (intr_mask & (0x00000001 << (i - IRQ_OFFSET))) { | 170 | * lazy and Michal can clean it up to something nicer when he tests |
151 | irq_set_chip_and_handler_name(i, &intc_dev, | 171 | * and commits this patch. ~~gcl */ |
152 | handle_edge_irq, "edge"); | 172 | root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops, |
153 | irq_clear_status_flags(i, IRQ_LEVEL); | 173 | (void *)intr_mask); |
154 | } else { | ||
155 | irq_set_chip_and_handler_name(i, &intc_dev, | ||
156 | handle_level_irq, "level"); | ||
157 | irq_set_status_flags(i, IRQ_LEVEL); | ||
158 | } | ||
159 | irq_get_irq_data(i)->hwirq = i - IRQ_OFFSET; | ||
160 | } | ||
161 | } | 174 | } |
diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c index bbebcae72c02..ace700afbfdf 100644 --- a/arch/microblaze/kernel/irq.c +++ b/arch/microblaze/kernel/irq.c | |||
@@ -31,14 +31,13 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
31 | trace_hardirqs_off(); | 31 | trace_hardirqs_off(); |
32 | 32 | ||
33 | irq_enter(); | 33 | irq_enter(); |
34 | irq = get_irq(regs); | 34 | irq = get_irq(); |
35 | next_irq: | 35 | next_irq: |
36 | BUG_ON(!irq); | 36 | BUG_ON(!irq); |
37 | /* Substract 1 because of get_irq */ | 37 | generic_handle_irq(irq); |
38 | generic_handle_irq(irq + IRQ_OFFSET - NO_IRQ_OFFSET); | ||
39 | 38 | ||
40 | irq = get_irq(regs); | 39 | irq = get_irq(); |
41 | if (irq) { | 40 | if (irq != -1U) { |
42 | pr_debug("next irq: %d\n", irq); | 41 | pr_debug("next irq: %d\n", irq); |
43 | ++concurrent_irq; | 42 | ++concurrent_irq; |
44 | goto next_irq; | 43 | goto next_irq; |
@@ -48,18 +47,3 @@ next_irq: | |||
48 | set_irq_regs(old_regs); | 47 | set_irq_regs(old_regs); |
49 | trace_hardirqs_on(); | 48 | trace_hardirqs_on(); |
50 | } | 49 | } |
51 | |||
52 | /* MS: There is no any advance mapping mechanism. We are using simple 32bit | ||
53 | intc without any cascades or any connection that's why mapping is 1:1 */ | ||
54 | unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq) | ||
55 | { | ||
56 | return hwirq + IRQ_OFFSET; | ||
57 | } | ||
58 | EXPORT_SYMBOL_GPL(irq_create_mapping); | ||
59 | |||
60 | unsigned int irq_create_of_mapping(struct device_node *controller, | ||
61 | const u32 *intspec, unsigned int intsize) | ||
62 | { | ||
63 | return intspec[0] + IRQ_OFFSET; | ||
64 | } | ||
65 | EXPORT_SYMBOL_GPL(irq_create_of_mapping); | ||
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index 604cd9dd1333..70e6d0b41ab4 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c | |||
@@ -51,8 +51,6 @@ void __init setup_arch(char **cmdline_p) | |||
51 | 51 | ||
52 | unflatten_device_tree(); | 52 | unflatten_device_tree(); |
53 | 53 | ||
54 | /* NOTE I think that this function is not necessary to call */ | ||
55 | /* irq_early_init(); */ | ||
56 | setup_cpuinfo(); | 54 | setup_cpuinfo(); |
57 | 55 | ||
58 | microblaze_cache_init(); | 56 | microblaze_cache_init(); |