diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-05 20:38:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-05 20:38:45 -0400 |
commit | 08d69a25714429850cf9ef71f22d8cdc9189d93f (patch) | |
tree | c03f4e91834b5280a4695f0c805b58c599e895cc /arch/openrisc | |
parent | ed5c41d30ef2ce578fd6b6e2f7ec23f2a58b1eba (diff) | |
parent | c6f1224573c3b609bd8073b39f496637a16cc06f (diff) |
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq updates from Thomas Gleixner:
"Nothing spectacular from the irq department this time:
- overhaul of the crossbar chip driver
- overhaul of the spear shirq chip driver
- support for the atmel-aic chip
- code move from arch to drivers
- the usual tiny fixlets
- two reverts worth to mention which undo the too simple attempt of
supporting wakeup interrupts on shared interrupt lines"
* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (41 commits)
Revert "irq: Warn when shared interrupts do not match on NO_SUSPEND"
Revert "PM / sleep / irq: Do not suspend wakeup interrupts"
irq: Warn when shared interrupts do not match on NO_SUSPEND
irqchip: atmel-aic: Define irq fixups for atmel SoCs
irqchip: atmel-aic: Implement RTC irq fixup
irqchip: atmel-aic: Add irq fixup infrastructure
irqchip: atmel-aic: Add atmel AIC/AIC5 drivers
irqchip: atmel-aic: Move binding doc to interrupt-controller directory
genirq: generic chip: Export irq_map_generic_chip function
PM / sleep / irq: Do not suspend wakeup interrupts
irqchip: or1k-pic: Migrate from arch/openrisc/
irqchip: crossbar: Allow for quirky hardware with direct hardwiring of GIC
documentation: dt: omap: crossbar: Add description for interrupt consumer
irqchip: crossbar: Introduce centralized check for crossbar write
irqchip: crossbar: Introduce ti, max-crossbar-sources to identify valid crossbar mapping
irqchip: crossbar: Add kerneldoc for crossbar_domain_unmap callback
irqchip: crossbar: Set cb pointer to null in case of error
irqchip: crossbar: Change the goto naming
irqchip: crossbar: Return proper error value
irqchip: crossbar: Fix kerneldoc warning
...
Diffstat (limited to 'arch/openrisc')
-rw-r--r-- | arch/openrisc/Kconfig | 1 | ||||
-rw-r--r-- | arch/openrisc/include/asm/irq.h | 3 | ||||
-rw-r--r-- | arch/openrisc/kernel/irq.c | 146 |
3 files changed, 17 insertions, 133 deletions
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig index e71d712afb79..88e83368bbf5 100644 --- a/arch/openrisc/Kconfig +++ b/arch/openrisc/Kconfig | |||
@@ -22,6 +22,7 @@ config OPENRISC | |||
22 | select GENERIC_STRNLEN_USER | 22 | select GENERIC_STRNLEN_USER |
23 | select MODULES_USE_ELF_RELA | 23 | select MODULES_USE_ELF_RELA |
24 | select HAVE_DEBUG_STACKOVERFLOW | 24 | select HAVE_DEBUG_STACKOVERFLOW |
25 | select OR1K_PIC | ||
25 | 26 | ||
26 | config MMU | 27 | config MMU |
27 | def_bool y | 28 | def_bool y |
diff --git a/arch/openrisc/include/asm/irq.h b/arch/openrisc/include/asm/irq.h index eb612b1865d2..b84634cc95eb 100644 --- a/arch/openrisc/include/asm/irq.h +++ b/arch/openrisc/include/asm/irq.h | |||
@@ -24,4 +24,7 @@ | |||
24 | 24 | ||
25 | #define NO_IRQ (-1) | 25 | #define NO_IRQ (-1) |
26 | 26 | ||
27 | void handle_IRQ(unsigned int, struct pt_regs *); | ||
28 | extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); | ||
29 | |||
27 | #endif /* __ASM_OPENRISC_IRQ_H__ */ | 30 | #endif /* __ASM_OPENRISC_IRQ_H__ */ |
diff --git a/arch/openrisc/kernel/irq.c b/arch/openrisc/kernel/irq.c index 8ec77bc9f1e7..967eb1430203 100644 --- a/arch/openrisc/kernel/irq.c +++ b/arch/openrisc/kernel/irq.c | |||
@@ -16,11 +16,10 @@ | |||
16 | 16 | ||
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/of.h> | ||
20 | #include <linux/ftrace.h> | 19 | #include <linux/ftrace.h> |
21 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
21 | #include <linux/irqchip.h> | ||
22 | #include <linux/export.h> | 22 | #include <linux/export.h> |
23 | #include <linux/irqdomain.h> | ||
24 | #include <linux/irqflags.h> | 23 | #include <linux/irqflags.h> |
25 | 24 | ||
26 | /* read interrupt enabled status */ | 25 | /* read interrupt enabled status */ |
@@ -37,150 +36,31 @@ void arch_local_irq_restore(unsigned long flags) | |||
37 | } | 36 | } |
38 | EXPORT_SYMBOL(arch_local_irq_restore); | 37 | EXPORT_SYMBOL(arch_local_irq_restore); |
39 | 38 | ||
40 | 39 | void __init init_IRQ(void) | |
41 | /* OR1K PIC implementation */ | ||
42 | |||
43 | /* We're a couple of cycles faster than the generic implementations with | ||
44 | * these 'fast' versions. | ||
45 | */ | ||
46 | |||
47 | static void or1k_pic_mask(struct irq_data *data) | ||
48 | { | ||
49 | mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq)); | ||
50 | } | ||
51 | |||
52 | static void or1k_pic_unmask(struct irq_data *data) | ||
53 | { | ||
54 | mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->hwirq)); | ||
55 | } | ||
56 | |||
57 | static void or1k_pic_ack(struct irq_data *data) | ||
58 | { | ||
59 | /* EDGE-triggered interrupts need to be ack'ed in order to clear | ||
60 | * the latch. | ||
61 | * LEVEL-triggered interrupts do not need to be ack'ed; however, | ||
62 | * ack'ing the interrupt has no ill-effect and is quicker than | ||
63 | * trying to figure out what type it is... | ||
64 | */ | ||
65 | |||
66 | /* The OpenRISC 1000 spec says to write a 1 to the bit to ack the | ||
67 | * interrupt, but the OR1200 does this backwards and requires a 0 | ||
68 | * to be written... | ||
69 | */ | ||
70 | |||
71 | #ifdef CONFIG_OR1K_1200 | ||
72 | /* There are two oddities with the OR1200 PIC implementation: | ||
73 | * i) LEVEL-triggered interrupts are latched and need to be cleared | ||
74 | * ii) the interrupt latch is cleared by writing a 0 to the bit, | ||
75 | * as opposed to a 1 as mandated by the spec | ||
76 | */ | ||
77 | |||
78 | mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq)); | ||
79 | #else | ||
80 | WARN(1, "Interrupt handling possibly broken\n"); | ||
81 | mtspr(SPR_PICSR, (1UL << data->hwirq)); | ||
82 | #endif | ||
83 | } | ||
84 | |||
85 | static void or1k_pic_mask_ack(struct irq_data *data) | ||
86 | { | ||
87 | /* Comments for pic_ack apply here, too */ | ||
88 | |||
89 | #ifdef CONFIG_OR1K_1200 | ||
90 | mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq)); | ||
91 | mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq)); | ||
92 | #else | ||
93 | WARN(1, "Interrupt handling possibly broken\n"); | ||
94 | mtspr(SPR_PICMR, (1UL << data->hwirq)); | ||
95 | mtspr(SPR_PICSR, (1UL << data->hwirq)); | ||
96 | #endif | ||
97 | } | ||
98 | |||
99 | #if 0 | ||
100 | static int or1k_pic_set_type(struct irq_data *data, unsigned int flow_type) | ||
101 | { | ||
102 | /* There's nothing to do in the PIC configuration when changing | ||
103 | * flow type. Level and edge-triggered interrupts are both | ||
104 | * supported, but it's PIC-implementation specific which type | ||
105 | * is handled. */ | ||
106 | |||
107 | return irq_setup_alt_chip(data, flow_type); | ||
108 | } | ||
109 | #endif | ||
110 | |||
111 | static struct irq_chip or1k_dev = { | ||
112 | .name = "or1k-PIC", | ||
113 | .irq_unmask = or1k_pic_unmask, | ||
114 | .irq_mask = or1k_pic_mask, | ||
115 | .irq_ack = or1k_pic_ack, | ||
116 | .irq_mask_ack = or1k_pic_mask_ack, | ||
117 | }; | ||
118 | |||
119 | static struct irq_domain *root_domain; | ||
120 | |||
121 | static inline int pic_get_irq(int first) | ||
122 | { | ||
123 | int hwirq; | ||
124 | |||
125 | hwirq = ffs(mfspr(SPR_PICSR) >> first); | ||
126 | if (!hwirq) | ||
127 | return NO_IRQ; | ||
128 | else | ||
129 | hwirq = hwirq + first -1; | ||
130 | |||
131 | return irq_find_mapping(root_domain, hwirq); | ||
132 | } | ||
133 | |||
134 | |||
135 | static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) | ||
136 | { | 40 | { |
137 | irq_set_chip_and_handler_name(irq, &or1k_dev, | 41 | irqchip_init(); |
138 | handle_level_irq, "level"); | ||
139 | irq_set_status_flags(irq, IRQ_LEVEL | IRQ_NOPROBE); | ||
140 | |||
141 | return 0; | ||
142 | } | 42 | } |
143 | 43 | ||
144 | static const struct irq_domain_ops or1k_irq_domain_ops = { | 44 | static void (*handle_arch_irq)(struct pt_regs *); |
145 | .xlate = irq_domain_xlate_onecell, | ||
146 | .map = or1k_map, | ||
147 | }; | ||
148 | |||
149 | /* | ||
150 | * This sets up the IRQ domain for the PIC built in to the OpenRISC | ||
151 | * 1000 CPU. This is the "root" domain as these are the interrupts | ||
152 | * that directly trigger an exception in the CPU. | ||
153 | */ | ||
154 | static void __init or1k_irq_init(void) | ||
155 | { | ||
156 | struct device_node *intc = NULL; | ||
157 | |||
158 | /* The interrupt controller device node is mandatory */ | ||
159 | intc = of_find_compatible_node(NULL, NULL, "opencores,or1k-pic"); | ||
160 | BUG_ON(!intc); | ||
161 | |||
162 | /* Disable all interrupts until explicitly requested */ | ||
163 | mtspr(SPR_PICMR, (0UL)); | ||
164 | |||
165 | root_domain = irq_domain_add_linear(intc, 32, | ||
166 | &or1k_irq_domain_ops, NULL); | ||
167 | } | ||
168 | 45 | ||
169 | void __init init_IRQ(void) | 46 | void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) |
170 | { | 47 | { |
171 | or1k_irq_init(); | 48 | handle_arch_irq = handle_irq; |
172 | } | 49 | } |
173 | 50 | ||
174 | void __irq_entry do_IRQ(struct pt_regs *regs) | 51 | void handle_IRQ(unsigned int irq, struct pt_regs *regs) |
175 | { | 52 | { |
176 | int irq = -1; | ||
177 | struct pt_regs *old_regs = set_irq_regs(regs); | 53 | struct pt_regs *old_regs = set_irq_regs(regs); |
178 | 54 | ||
179 | irq_enter(); | 55 | irq_enter(); |
180 | 56 | ||
181 | while ((irq = pic_get_irq(irq + 1)) != NO_IRQ) | 57 | generic_handle_irq(irq); |
182 | generic_handle_irq(irq); | ||
183 | 58 | ||
184 | irq_exit(); | 59 | irq_exit(); |
185 | set_irq_regs(old_regs); | 60 | set_irq_regs(old_regs); |
186 | } | 61 | } |
62 | |||
63 | void __irq_entry do_IRQ(struct pt_regs *regs) | ||
64 | { | ||
65 | handle_arch_irq(regs); | ||
66 | } | ||