initial commit with v2.6.9
[linux-2.6.9-moxart.git] / arch / cris / kernel / irq.c
blobbb8d2e4e7a9c9a625e9e766cd2b8e50792ace30c
1 /*
3 * linux/arch/cris/kernel/irq.c
5 * Copyright (c) 2000,2001 Axis Communications AB
7 * Authors: Bjorn Wesen (bjornw@axis.com)
9 * This file contains the code used by various IRQ handling routines:
10 * asking for different IRQ's should be done through these routines
11 * instead of just grabbing them. Thus setups with different IRQ numbers
12 * shouldn't result in any weird surprises, and installing new handlers
13 * should be easier.
15 * Notice Linux/CRIS: these routines do not care about SMP
20 * IRQ's are in fact implemented a bit like signal handlers for the kernel.
21 * Naturally it's not a 1:1 relation, but there are similarities.
24 #include <linux/config.h>
25 #include <linux/module.h>
26 #include <linux/ptrace.h>
28 #include <linux/kernel_stat.h>
29 #include <linux/signal.h>
30 #include <linux/sched.h>
31 #include <linux/ioport.h>
32 #include <linux/interrupt.h>
33 #include <linux/timex.h>
34 #include <linux/slab.h>
35 #include <linux/random.h>
36 #include <linux/init.h>
37 #include <linux/seq_file.h>
38 #include <linux/errno.h>
40 #include <asm/io.h>
41 #include <asm/bitops.h>
43 /* Defined in arch specific irq.c */
44 extern void arch_setup_irq(int irq);
45 extern void arch_free_irq(int irq);
47 void
48 disable_irq(unsigned int irq_nr)
50 unsigned long flags;
52 local_save_flags(flags);
53 local_irq_disable();
54 mask_irq(irq_nr);
55 local_irq_restore(flags);
58 void
59 enable_irq(unsigned int irq_nr)
61 unsigned long flags;
62 local_save_flags(flags);
63 local_irq_disable();
64 unmask_irq(irq_nr);
65 local_irq_restore(flags);
68 unsigned long
69 probe_irq_on()
71 return 0;
74 EXPORT_SYMBOL(probe_irq_on);
76 int
77 probe_irq_off(unsigned long x)
79 return 0;
82 EXPORT_SYMBOL(probe_irq_off);
85 * Initial irq handlers.
88 static struct irqaction *irq_action[NR_IRQS];
90 int show_interrupts(struct seq_file *p, void *v)
92 int i = *(loff_t *) v;
93 struct irqaction * action;
94 unsigned long flags;
96 if (i < NR_IRQS) {
97 local_irq_save(flags);
98 action = irq_action[i];
99 if (!action)
100 goto skip;
101 seq_printf(p, "%2d: %10u %c %s",
102 i, kstat_this_cpu.irqs[i],
103 (action->flags & SA_INTERRUPT) ? '+' : ' ',
104 action->name);
105 for (action = action->next; action; action = action->next) {
106 seq_printf(p, ",%s %s",
107 (action->flags & SA_INTERRUPT) ? " +" : "",
108 action->name);
110 seq_putc(p, '\n');
111 skip:
112 local_irq_restore(flags);
114 return 0;
117 /* called by the assembler IRQ entry functions defined in irq.h
118 * to dispatch the interrupts to registred handlers
119 * interrupts are disabled upon entry - depending on if the
120 * interrupt was registred with SA_INTERRUPT or not, interrupts
121 * are re-enabled or not.
124 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
126 struct irqaction *action;
127 int do_random, cpu;
128 int ret, retval = 0;
130 cpu = smp_processor_id();
131 irq_enter();
132 kstat_cpu(cpu).irqs[irq - FIRST_IRQ]++;
133 action = irq_action[irq - FIRST_IRQ];
135 if (action) {
136 if (!(action->flags & SA_INTERRUPT))
137 local_irq_enable();
138 do_random = 0;
139 do {
140 ret = action->handler(irq, action->dev_id, regs);
141 if (ret == IRQ_HANDLED)
142 do_random |= action->flags;
143 retval |= ret;
144 action = action->next;
145 } while (action);
147 if (retval != 1) {
148 if (retval) {
149 printk("irq event %d: bogus retval mask %x\n",
150 irq, retval);
151 } else {
152 printk("irq %d: nobody cared\n", irq);
156 if (do_random & SA_SAMPLE_RANDOM)
157 add_interrupt_randomness(irq);
158 local_irq_disable();
160 irq_exit();
162 if (softirq_pending(cpu))
163 do_softirq();
165 /* unmasking and bottom half handling is done magically for us. */
168 /* this function links in a handler into the chain of handlers for the
169 given irq, and if the irq has never been registred, the appropriate
170 handler is entered into the interrupt vector
173 int setup_irq(int irq, struct irqaction * new)
175 int shared = 0;
176 struct irqaction *old, **p;
177 unsigned long flags;
179 p = irq_action + irq - FIRST_IRQ;
180 if ((old = *p) != NULL) {
181 /* Can't share interrupts unless both agree to */
182 if (!(old->flags & new->flags & SA_SHIRQ))
183 return -EBUSY;
185 /* Can't share interrupts unless both are same type */
186 if ((old->flags ^ new->flags) & SA_INTERRUPT)
187 return -EBUSY;
189 /* add new interrupt at end of irq queue */
190 do {
191 p = &old->next;
192 old = *p;
193 } while (old);
194 shared = 1;
197 if (new->flags & SA_SAMPLE_RANDOM)
198 rand_initialize_irq(irq);
200 local_save_flags(flags);
201 local_irq_disable();
202 *p = new;
204 if (!shared) {
205 /* if the irq wasn't registred before, enter it into the vector table
206 and unmask it physically
208 arch_setup_irq(irq);
209 unmask_irq(irq);
212 local_irq_restore(flags);
213 return 0;
216 /* this function is called by a driver to register an irq handler
217 Valid flags:
218 SA_INTERRUPT -> it's a fast interrupt, handler called with irq disabled and
219 no signal checking etc is performed upon exit
220 SA_SHIRQ -> the interrupt can be shared between different handlers, the handler
221 is required to check if the irq was "aimed" at it explicitely
222 SA_RANDOM -> the interrupt will add to the random generators entropy
225 int request_irq(unsigned int irq,
226 irqreturn_t (*handler)(int, void *, struct pt_regs *),
227 unsigned long irqflags,
228 const char * devname,
229 void *dev_id)
231 int retval;
232 struct irqaction * action;
234 if(!handler)
235 return -EINVAL;
237 /* allocate and fill in a handler structure and setup the irq */
239 action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
240 if (!action)
241 return -ENOMEM;
243 action->handler = handler;
244 action->flags = irqflags;
245 cpus_clear(action->mask);
246 action->name = devname;
247 action->next = NULL;
248 action->dev_id = dev_id;
250 retval = setup_irq(irq, action);
252 if (retval)
253 kfree(action);
254 return retval;
257 EXPORT_SYMBOL(request_irq);
259 void free_irq(unsigned int irq, void *dev_id)
261 struct irqaction * action, **p;
262 unsigned long flags;
264 if (irq >= NR_IRQS) {
265 printk("Trying to free IRQ%d\n",irq);
266 return;
268 for (p = irq - FIRST_IRQ + irq_action; (action = *p) != NULL; p = &action->next) {
269 if (action->dev_id != dev_id)
270 continue;
272 /* Found it - now free it */
273 local_save_flags(flags);
274 local_irq_disable();
275 *p = action->next;
276 if (!irq_action[irq - FIRST_IRQ]) {
277 mask_irq(irq);
278 arch_free_irq(irq);
280 local_irq_restore(flags);
281 kfree(action);
282 return;
284 printk("Trying to free free IRQ%d\n",irq);
287 EXPORT_SYMBOL(free_irq);
289 void weird_irq(void)
291 local_irq_disable();
292 printk("weird irq\n");
293 while(1);
296 #if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
297 /* Used by other archs to show/control IRQ steering during SMP */
298 void __init
299 init_irq_proc(void)
302 #endif