diff options
author | Roman Zippel <zippel@linux-m68k.org> | 2006-06-25 08:47:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-25 13:00:57 -0400 |
commit | b5dc7840b3ebe9c7967dd8ba73db957767009ff9 (patch) | |
tree | 0c5d45c592f140937e4e3e49ac9bc4ea8fc2cef7 /arch/m68k/kernel | |
parent | 1d174cfb0f2a8967433e157bae9c2d4dcdee5324 (diff) |
[PATCH] m68k: introduce irq controller
Introduce irq controller and use it to manage auto vector interrupts.
Introduce setup_irq() which can be used for irq setup.
Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/m68k/kernel')
-rw-r--r-- | arch/m68k/kernel/ints.c | 171 |
1 files changed, 123 insertions, 48 deletions
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c index 3ce7c6166bb9..c7f6ee67fd5a 100644 --- a/arch/m68k/kernel/ints.c +++ b/arch/m68k/kernel/ints.c | |||
@@ -45,7 +45,15 @@ | |||
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | /* table for system interrupt handlers */ | 47 | /* table for system interrupt handlers */ |
48 | static irq_handler_t irq_list[SYS_IRQS]; | 48 | static struct irq_node *irq_list[SYS_IRQS]; |
49 | static struct irq_controller *irq_controller[SYS_IRQS]; | ||
50 | |||
51 | static struct irq_controller auto_irq_controller = { | ||
52 | .name = "auto", | ||
53 | .lock = SPIN_LOCK_UNLOCKED, | ||
54 | .startup = m68k_irq_startup, | ||
55 | .shutdown = m68k_irq_shutdown, | ||
56 | }; | ||
49 | 57 | ||
50 | static const char *default_names[SYS_IRQS] = { | 58 | static const char *default_names[SYS_IRQS] = { |
51 | [0] = "spurious int", | 59 | [0] = "spurious int", |
@@ -101,17 +109,13 @@ void __init init_IRQ(void) | |||
101 | hardirq_mask_is_broken(); | 109 | hardirq_mask_is_broken(); |
102 | } | 110 | } |
103 | 111 | ||
104 | for (i = 0; i < SYS_IRQS; i++) { | 112 | for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) { |
105 | if (mach_default_handler) | 113 | irq_controller[i] = &auto_irq_controller; |
106 | irq_list[i].handler = (*mach_default_handler)[i]; | 114 | if (mach_default_handler && (*mach_default_handler)[i]) |
107 | irq_list[i].flags = 0; | 115 | cpu_request_irq(i, (*mach_default_handler)[i], |
108 | irq_list[i].dev_id = NULL; | 116 | 0, default_names[i], NULL); |
109 | irq_list[i].devname = default_names[i]; | ||
110 | } | 117 | } |
111 | 118 | ||
112 | for (i = 0; i < NUM_IRQ_NODES; i++) | ||
113 | nodes[i].handler = NULL; | ||
114 | |||
115 | mach_init_IRQ (); | 119 | mach_init_IRQ (); |
116 | } | 120 | } |
117 | 121 | ||
@@ -120,9 +124,12 @@ irq_node_t *new_irq_node(void) | |||
120 | irq_node_t *node; | 124 | irq_node_t *node; |
121 | short i; | 125 | short i; |
122 | 126 | ||
123 | for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) | 127 | for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) { |
124 | if (!node->handler) | 128 | if (!node->handler) { |
129 | memset(node, 0, sizeof(*node)); | ||
125 | return node; | 130 | return node; |
131 | } | ||
132 | } | ||
126 | 133 | ||
127 | printk ("new_irq_node: out of nodes\n"); | 134 | printk ("new_irq_node: out of nodes\n"); |
128 | return NULL; | 135 | return NULL; |
@@ -149,55 +156,115 @@ void free_irq(unsigned int irq, void *dev_id) | |||
149 | 156 | ||
150 | EXPORT_SYMBOL(free_irq); | 157 | EXPORT_SYMBOL(free_irq); |
151 | 158 | ||
152 | int cpu_request_irq(unsigned int irq, | 159 | int setup_irq(unsigned int irq, struct irq_node *node) |
153 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
154 | unsigned long flags, const char *devname, void *dev_id) | ||
155 | { | 160 | { |
156 | if (irq < IRQ_AUTO_1 || irq > IRQ_AUTO_7) { | 161 | struct irq_controller *contr; |
162 | struct irq_node **prev; | ||
163 | unsigned long flags; | ||
164 | |||
165 | if (irq >= SYS_IRQS || !(contr = irq_controller[irq])) { | ||
157 | printk("%s: Incorrect IRQ %d from %s\n", | 166 | printk("%s: Incorrect IRQ %d from %s\n", |
158 | __FUNCTION__, irq, devname); | 167 | __FUNCTION__, irq, node->devname); |
159 | return -ENXIO; | 168 | return -ENXIO; |
160 | } | 169 | } |
161 | 170 | ||
162 | #if 0 | 171 | spin_lock_irqsave(&contr->lock, flags); |
163 | if (!(irq_list[irq].flags & IRQ_FLG_STD)) { | 172 | |
164 | if (irq_list[irq].flags & IRQ_FLG_LOCK) { | 173 | prev = irq_list + irq; |
165 | printk("%s: IRQ %d from %s is not replaceable\n", | 174 | if (*prev) { |
166 | __FUNCTION__, irq, irq_list[irq].devname); | 175 | /* Can't share interrupts unless both agree to */ |
167 | return -EBUSY; | 176 | if (!((*prev)->flags & node->flags & SA_SHIRQ)) { |
168 | } | 177 | spin_unlock_irqrestore(&contr->lock, flags); |
169 | if (!(flags & IRQ_FLG_REPLACE)) { | ||
170 | printk("%s: %s can't replace IRQ %d from %s\n", | ||
171 | __FUNCTION__, devname, irq, irq_list[irq].devname); | ||
172 | return -EBUSY; | 178 | return -EBUSY; |
173 | } | 179 | } |
180 | while (*prev) | ||
181 | prev = &(*prev)->next; | ||
174 | } | 182 | } |
175 | #endif | ||
176 | 183 | ||
177 | irq_list[irq].handler = handler; | 184 | if (!irq_list[irq]) { |
178 | irq_list[irq].flags = flags; | 185 | if (contr->startup) |
179 | irq_list[irq].dev_id = dev_id; | 186 | contr->startup(irq); |
180 | irq_list[irq].devname = devname; | 187 | else |
188 | contr->enable(irq); | ||
189 | } | ||
190 | node->next = NULL; | ||
191 | *prev = node; | ||
192 | |||
193 | spin_unlock_irqrestore(&contr->lock, flags); | ||
194 | |||
181 | return 0; | 195 | return 0; |
182 | } | 196 | } |
183 | 197 | ||
198 | int cpu_request_irq(unsigned int irq, | ||
199 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
200 | unsigned long flags, const char *devname, void *dev_id) | ||
201 | { | ||
202 | struct irq_node *node; | ||
203 | int res; | ||
204 | |||
205 | node = new_irq_node(); | ||
206 | if (!node) | ||
207 | return -ENOMEM; | ||
208 | |||
209 | node->handler = handler; | ||
210 | node->flags = flags; | ||
211 | node->dev_id = dev_id; | ||
212 | node->devname = devname; | ||
213 | |||
214 | res = setup_irq(irq, node); | ||
215 | if (res) | ||
216 | node->handler = NULL; | ||
217 | |||
218 | return res; | ||
219 | } | ||
220 | |||
184 | void cpu_free_irq(unsigned int irq, void *dev_id) | 221 | void cpu_free_irq(unsigned int irq, void *dev_id) |
185 | { | 222 | { |
186 | if (irq < IRQ_AUTO_1 || irq > IRQ_AUTO_7) { | 223 | struct irq_controller *contr; |
224 | struct irq_node **p, *node; | ||
225 | unsigned long flags; | ||
226 | |||
227 | if (irq >= SYS_IRQS || !(contr = irq_controller[irq])) { | ||
187 | printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); | 228 | printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); |
188 | return; | 229 | return; |
189 | } | 230 | } |
190 | 231 | ||
191 | if (irq_list[irq].dev_id != dev_id) | 232 | spin_lock_irqsave(&contr->lock, flags); |
192 | printk("%s: Removing probably wrong IRQ %d from %s\n", | 233 | |
193 | __FUNCTION__, irq, irq_list[irq].devname); | 234 | p = irq_list + irq; |
235 | while ((node = *p)) { | ||
236 | if (node->dev_id == dev_id) | ||
237 | break; | ||
238 | p = &node->next; | ||
239 | } | ||
240 | |||
241 | if (node) { | ||
242 | *p = node->next; | ||
243 | node->handler = NULL; | ||
244 | } else | ||
245 | printk("%s: Removing probably wrong IRQ %d\n", | ||
246 | __FUNCTION__, irq); | ||
247 | |||
248 | if (!irq_list[irq]) | ||
249 | contr->shutdown(irq); | ||
194 | 250 | ||
195 | irq_list[irq].handler = (*mach_default_handler)[irq]; | 251 | spin_unlock_irqrestore(&contr->lock, flags); |
196 | irq_list[irq].flags = 0; | ||
197 | irq_list[irq].dev_id = NULL; | ||
198 | irq_list[irq].devname = default_names[irq]; | ||
199 | } | 252 | } |
200 | 253 | ||
254 | int m68k_irq_startup(unsigned int irq) | ||
255 | { | ||
256 | if (irq <= IRQ_AUTO_7) | ||
257 | vectors[VEC_SPUR + irq] = auto_inthandler; | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | void m68k_irq_shutdown(unsigned int irq) | ||
262 | { | ||
263 | if (irq <= IRQ_AUTO_7) | ||
264 | vectors[VEC_SPUR + irq] = bad_inthandler; | ||
265 | } | ||
266 | |||
267 | |||
201 | /* | 268 | /* |
202 | * Do we need these probe functions on the m68k? | 269 | * Do we need these probe functions on the m68k? |
203 | * | 270 | * |
@@ -250,8 +317,14 @@ static void dummy_free_irq(unsigned int irq, void *dev_id) | |||
250 | 317 | ||
251 | asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs) | 318 | asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs) |
252 | { | 319 | { |
320 | struct irq_node *node; | ||
321 | |||
253 | kstat_cpu(0).irqs[irq]++; | 322 | kstat_cpu(0).irqs[irq]++; |
254 | irq_list[irq].handler(irq, irq_list[irq].dev_id, regs); | 323 | node = irq_list[irq]; |
324 | do { | ||
325 | node->handler(irq, node->dev_id, regs); | ||
326 | node = node->next; | ||
327 | } while (node); | ||
255 | } | 328 | } |
256 | 329 | ||
257 | asmlinkage void handle_badint(struct pt_regs *regs) | 330 | asmlinkage void handle_badint(struct pt_regs *regs) |
@@ -262,16 +335,18 @@ asmlinkage void handle_badint(struct pt_regs *regs) | |||
262 | 335 | ||
263 | int show_interrupts(struct seq_file *p, void *v) | 336 | int show_interrupts(struct seq_file *p, void *v) |
264 | { | 337 | { |
338 | struct irq_controller *contr; | ||
339 | struct irq_node *node; | ||
265 | int i = *(loff_t *) v; | 340 | int i = *(loff_t *) v; |
266 | 341 | ||
267 | /* autovector interrupts */ | 342 | /* autovector interrupts */ |
268 | if (i < SYS_IRQS) { | 343 | if (i < SYS_IRQS && irq_list[i]) { |
269 | if (mach_default_handler) { | 344 | contr = irq_controller[i]; |
270 | seq_printf(p, "auto %2d: %10u ", i, | 345 | node = irq_list[i]; |
271 | i ? kstat_cpu(0).irqs[i] : num_spurious); | 346 | seq_printf(p, "%s %u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname); |
272 | seq_puts(p, " "); | 347 | while ((node = node->next)) |
273 | seq_printf(p, "%s\n", irq_list[i].devname); | 348 | seq_printf(p, ", %s", node->devname); |
274 | } | 349 | seq_puts(p, "\n"); |
275 | } else if (i == SYS_IRQS) | 350 | } else if (i == SYS_IRQS) |
276 | mach_get_irq_list(p, v); | 351 | mach_get_irq_list(p, v); |
277 | return 0; | 352 | return 0; |