aboutsummaryrefslogtreecommitdiffstats
path: root/arch/cris
diff options
context:
space:
mode:
Diffstat (limited to 'arch/cris')
-rw-r--r--arch/cris/arch-v10/kernel/irq.c76
-rw-r--r--arch/cris/kernel/irq.c263
2 files changed, 83 insertions, 256 deletions
diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c
index b2f16d6fc871..4b368a122015 100644
--- a/arch/cris/arch-v10/kernel/irq.c
+++ b/arch/cris/arch-v10/kernel/irq.c
@@ -1,4 +1,4 @@
1/* $Id: irq.c,v 1.2 2004/06/09 05:30:27 starvik Exp $ 1/* $Id: irq.c,v 1.4 2005/01/04 12:22:28 starvik Exp $
2 * 2 *
3 * linux/arch/cris/kernel/irq.c 3 * linux/arch/cris/kernel/irq.c
4 * 4 *
@@ -12,11 +12,13 @@
12 */ 12 */
13 13
14#include <asm/irq.h> 14#include <asm/irq.h>
15#include <linux/irq.h>
15#include <linux/kernel.h> 16#include <linux/kernel.h>
16#include <linux/init.h> 17#include <linux/init.h>
17#include <linux/config.h> 18#include <linux/config.h>
18 19
19irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq prologue */ 20#define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
21#define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
20 22
21/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is 23/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is
22 * global just so that the kernel gdb can use it. 24 * global just so that the kernel gdb can use it.
@@ -102,41 +104,52 @@ static void (*interrupt[NR_IRQS])(void) = {
102 IRQ31_interrupt 104 IRQ31_interrupt
103}; 105};
104 106
105static void (*bad_interrupt[NR_IRQS])(void) = { 107static void enable_crisv10_irq(unsigned int irq);
106 NULL, NULL, 108
107 NULL, bad_IRQ3_interrupt, 109static unsigned int startup_crisv10_irq(unsigned int irq)
108 bad_IRQ4_interrupt, bad_IRQ5_interrupt, 110{
109 bad_IRQ6_interrupt, bad_IRQ7_interrupt, 111 enable_crisv10_irq(irq);
110 bad_IRQ8_interrupt, bad_IRQ9_interrupt, 112 return 0;
111 bad_IRQ10_interrupt, bad_IRQ11_interrupt, 113}
112 bad_IRQ12_interrupt, bad_IRQ13_interrupt, 114
113 NULL, NULL, 115#define shutdown_crisv10_irq disable_crisv10_irq
114 bad_IRQ16_interrupt, bad_IRQ17_interrupt,
115 bad_IRQ18_interrupt, bad_IRQ19_interrupt,
116 bad_IRQ20_interrupt, bad_IRQ21_interrupt,
117 bad_IRQ22_interrupt, bad_IRQ23_interrupt,
118 bad_IRQ24_interrupt, bad_IRQ25_interrupt,
119 NULL, NULL, NULL, NULL, NULL,
120 bad_IRQ31_interrupt
121};
122 116
123void arch_setup_irq(int irq) 117static void enable_crisv10_irq(unsigned int irq)
124{ 118{
125 set_int_vector(irq, interrupt[irq]); 119 unmask_irq(irq);
126} 120}
127 121
128void arch_free_irq(int irq) 122static void disable_crisv10_irq(unsigned int irq)
129{ 123{
130 set_int_vector(irq, bad_interrupt[irq]); 124 mask_irq(irq);
131} 125}
132 126
127static void ack_crisv10_irq(unsigned int irq)
128{
129}
130
131static void end_crisv10_irq(unsigned int irq)
132{
133}
134
135static struct hw_interrupt_type crisv10_irq_type = {
136 .typename = "CRISv10",
137 .startup = startup_crisv10_irq,
138 .shutdown = shutdown_crisv10_irq,
139 .enable = enable_crisv10_irq,
140 .disable = disable_crisv10_irq,
141 .ack = ack_crisv10_irq,
142 .end = end_crisv10_irq,
143 .set_affinity = NULL
144};
145
133void weird_irq(void); 146void weird_irq(void);
134void system_call(void); /* from entry.S */ 147void system_call(void); /* from entry.S */
135void do_sigtrap(void); /* from entry.S */ 148void do_sigtrap(void); /* from entry.S */
136void gdb_handle_breakpoint(void); /* from entry.S */ 149void gdb_handle_breakpoint(void); /* from entry.S */
137 150
138/* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and 151/* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and
139 setting the irq vector table to point to bad_interrupt ptrs. 152 setting the irq vector table.
140*/ 153*/
141 154
142void __init 155void __init
@@ -154,14 +167,15 @@ init_IRQ(void)
154 167
155 *R_VECT_MASK_CLR = 0xffffffff; 168 *R_VECT_MASK_CLR = 0xffffffff;
156 169
157 /* clear the shortcut entry points */
158
159 for(i = 0; i < NR_IRQS; i++)
160 irq_shortcuts[i] = NULL;
161
162 for (i = 0; i < 256; i++) 170 for (i = 0; i < 256; i++)
163 etrax_irv->v[i] = weird_irq; 171 etrax_irv->v[i] = weird_irq;
164 172
173 /* Initialize IRQ handler descriptiors. */
174 for(i = 2; i < NR_IRQS; i++) {
175 irq_desc[i].handler = &crisv10_irq_type;
176 set_int_vector(i, interrupt[i]);
177 }
178
165 /* the entries in the break vector contain actual code to be 179 /* the entries in the break vector contain actual code to be
166 executed by the associated break handler, rather than just a jump 180 executed by the associated break handler, rather than just a jump
167 address. therefore we need to setup a default breakpoint handler 181 address. therefore we need to setup a default breakpoint handler
@@ -170,10 +184,6 @@ init_IRQ(void)
170 for (i = 0; i < 16; i++) 184 for (i = 0; i < 16; i++)
171 set_break_vector(i, do_sigtrap); 185 set_break_vector(i, do_sigtrap);
172 186
173 /* set all etrax irq's to the bad handlers */
174 for (i = 2; i < NR_IRQS; i++)
175 set_int_vector(i, bad_interrupt[i]);
176
177 /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ 187 /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
178 188
179 set_int_vector(15, multiple_interrupt); 189 set_int_vector(15, multiple_interrupt);
diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c
index d848b9407457..30deaf1b728a 100644
--- a/arch/cris/kernel/irq.c
+++ b/arch/cris/kernel/irq.c
@@ -12,8 +12,6 @@
12 * shouldn't result in any weird surprises, and installing new handlers 12 * shouldn't result in any weird surprises, and installing new handlers
13 * should be easier. 13 * should be easier.
14 * 14 *
15 * Notice Linux/CRIS: these routines do not care about SMP
16 *
17 */ 15 */
18 16
19/* 17/*
@@ -24,6 +22,7 @@
24#include <linux/config.h> 22#include <linux/config.h>
25#include <linux/module.h> 23#include <linux/module.h>
26#include <linux/ptrace.h> 24#include <linux/ptrace.h>
25#include <linux/irq.h>
27 26
28#include <linux/kernel_stat.h> 27#include <linux/kernel_stat.h>
29#include <linux/signal.h> 28#include <linux/signal.h>
@@ -36,84 +35,56 @@
36#include <linux/init.h> 35#include <linux/init.h>
37#include <linux/seq_file.h> 36#include <linux/seq_file.h>
38#include <linux/errno.h> 37#include <linux/errno.h>
39#include <linux/bitops.h> 38#include <linux/spinlock.h>
40 39
41#include <asm/io.h> 40#include <asm/io.h>
42 41
43/* Defined in arch specific irq.c */ 42void ack_bad_irq(unsigned int irq)
44extern void arch_setup_irq(int irq);
45extern void arch_free_irq(int irq);
46
47void
48disable_irq(unsigned int irq_nr)
49{
50 unsigned long flags;
51
52 local_save_flags(flags);
53 local_irq_disable();
54 mask_irq(irq_nr);
55 local_irq_restore(flags);
56}
57
58void
59enable_irq(unsigned int irq_nr)
60{ 43{
61 unsigned long flags; 44 printk("unexpected IRQ trap at vector %02x\n", irq);
62 local_save_flags(flags);
63 local_irq_disable();
64 unmask_irq(irq_nr);
65 local_irq_restore(flags);
66} 45}
67 46
68unsigned long
69probe_irq_on()
70{
71 return 0;
72}
73
74EXPORT_SYMBOL(probe_irq_on);
75
76int
77probe_irq_off(unsigned long x)
78{
79 return 0;
80}
81
82EXPORT_SYMBOL(probe_irq_off);
83
84/*
85 * Initial irq handlers.
86 */
87
88static struct irqaction *irq_action[NR_IRQS];
89
90int show_interrupts(struct seq_file *p, void *v) 47int show_interrupts(struct seq_file *p, void *v)
91{ 48{
92 int i = *(loff_t *) v; 49 int i = *(loff_t *) v, j;
93 struct irqaction * action; 50 struct irqaction * action;
94 unsigned long flags; 51 unsigned long flags;
95 52
53 if (i == 0) {
54 seq_printf(p, " ");
55 for (j=0; j<NR_CPUS; j++)
56 if (cpu_online(j))
57 seq_printf(p, "CPU%d ",j);
58 seq_putc(p, '\n');
59 }
60
96 if (i < NR_IRQS) { 61 if (i < NR_IRQS) {
97 local_irq_save(flags); 62 spin_lock_irqsave(&irq_desc[i].lock, flags);
98 action = irq_action[i]; 63 action = irq_desc[i].action;
99 if (!action) 64 if (!action)
100 goto skip; 65 goto skip;
101 seq_printf(p, "%2d: %10u %c %s", 66 seq_printf(p, "%3d: ",i);
102 i, kstat_this_cpu.irqs[i], 67#ifndef CONFIG_SMP
103 (action->flags & SA_INTERRUPT) ? '+' : ' ', 68 seq_printf(p, "%10u ", kstat_irqs(i));
104 action->name); 69#else
105 for (action = action->next; action; action = action->next) { 70 for (j = 0; j < NR_CPUS; j++)
106 seq_printf(p, ",%s %s", 71 if (cpu_online(j))
107 (action->flags & SA_INTERRUPT) ? " +" : "", 72 seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
108 action->name); 73#endif
109 } 74 seq_printf(p, " %14s", irq_desc[i].handler->typename);
75 seq_printf(p, " %s", action->name);
76
77 for (action=action->next; action; action = action->next)
78 seq_printf(p, ", %s", action->name);
79
110 seq_putc(p, '\n'); 80 seq_putc(p, '\n');
111skip: 81skip:
112 local_irq_restore(flags); 82 spin_unlock_irqrestore(&irq_desc[i].lock, flags);
113 } 83 }
114 return 0; 84 return 0;
115} 85}
116 86
87
117/* called by the assembler IRQ entry functions defined in irq.h 88/* called by the assembler IRQ entry functions defined in irq.h
118 * to dispatch the interrupts to registred handlers 89 * to dispatch the interrupts to registred handlers
119 * interrupts are disabled upon entry - depending on if the 90 * interrupts are disabled upon entry - depending on if the
@@ -123,164 +94,17 @@ skip:
123 94
124asmlinkage void do_IRQ(int irq, struct pt_regs * regs) 95asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
125{ 96{
126 struct irqaction *action; 97 unsigned long sp;
127 int do_random, cpu; 98 irq_enter();
128 int ret, retval = 0; 99 sp = rdsp();
129 100 if (unlikely((sp & (PAGE_SIZE - 1)) < (PAGE_SIZE/8))) {
130 cpu = smp_processor_id(); 101 printk("do_IRQ: stack overflow: %lX\n", sp);
131 irq_enter(); 102 show_stack(NULL, (unsigned long *)sp);
132 kstat_cpu(cpu).irqs[irq - FIRST_IRQ]++;
133 action = irq_action[irq - FIRST_IRQ];
134
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);
146
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);
153 }
154 }
155
156 if (do_random & SA_SAMPLE_RANDOM)
157 add_interrupt_randomness(irq);
158 local_irq_disable();
159 }
160 irq_exit();
161}
162
163/* this function links in a handler into the chain of handlers for the
164 given irq, and if the irq has never been registred, the appropriate
165 handler is entered into the interrupt vector
166*/
167
168int setup_irq(int irq, struct irqaction * new)
169{
170 int shared = 0;
171 struct irqaction *old, **p;
172 unsigned long flags;
173
174 p = irq_action + irq - FIRST_IRQ;
175 if ((old = *p) != NULL) {
176 /* Can't share interrupts unless both agree to */
177 if (!(old->flags & new->flags & SA_SHIRQ))
178 return -EBUSY;
179
180 /* Can't share interrupts unless both are same type */
181 if ((old->flags ^ new->flags) & SA_INTERRUPT)
182 return -EBUSY;
183
184 /* add new interrupt at end of irq queue */
185 do {
186 p = &old->next;
187 old = *p;
188 } while (old);
189 shared = 1;
190 }
191
192 if (new->flags & SA_SAMPLE_RANDOM)
193 rand_initialize_irq(irq);
194
195 local_save_flags(flags);
196 local_irq_disable();
197 *p = new;
198
199 if (!shared) {
200 /* if the irq wasn't registred before, enter it into the vector table
201 and unmask it physically
202 */
203 arch_setup_irq(irq);
204 unmask_irq(irq);
205 }
206
207 local_irq_restore(flags);
208 return 0;
209}
210
211/* this function is called by a driver to register an irq handler
212 Valid flags:
213 SA_INTERRUPT -> it's a fast interrupt, handler called with irq disabled and
214 no signal checking etc is performed upon exit
215 SA_SHIRQ -> the interrupt can be shared between different handlers, the handler
216 is required to check if the irq was "aimed" at it explicitely
217 SA_RANDOM -> the interrupt will add to the random generators entropy
218*/
219
220int request_irq(unsigned int irq,
221 irqreturn_t (*handler)(int, void *, struct pt_regs *),
222 unsigned long irqflags,
223 const char * devname,
224 void *dev_id)
225{
226 int retval;
227 struct irqaction * action;
228
229 if(!handler)
230 return -EINVAL;
231
232 /* allocate and fill in a handler structure and setup the irq */
233
234 action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
235 if (!action)
236 return -ENOMEM;
237
238 action->handler = handler;
239 action->flags = irqflags;
240 cpus_clear(action->mask);
241 action->name = devname;
242 action->next = NULL;
243 action->dev_id = dev_id;
244
245 retval = setup_irq(irq, action);
246
247 if (retval)
248 kfree(action);
249 return retval;
250}
251
252EXPORT_SYMBOL(request_irq);
253
254void free_irq(unsigned int irq, void *dev_id)
255{
256 struct irqaction * action, **p;
257 unsigned long flags;
258
259 if (irq >= NR_IRQS) {
260 printk("Trying to free IRQ%d\n",irq);
261 return;
262 } 103 }
263 for (p = irq - FIRST_IRQ + irq_action; (action = *p) != NULL; p = &action->next) { 104 __do_IRQ(irq, regs);
264 if (action->dev_id != dev_id) 105 irq_exit();
265 continue;
266
267 /* Found it - now free it */
268 local_save_flags(flags);
269 local_irq_disable();
270 *p = action->next;
271 if (!irq_action[irq - FIRST_IRQ]) {
272 mask_irq(irq);
273 arch_free_irq(irq);
274 }
275 local_irq_restore(flags);
276 kfree(action);
277 return;
278 }
279 printk("Trying to free free IRQ%d\n",irq);
280} 106}
281 107
282EXPORT_SYMBOL(free_irq);
283
284void weird_irq(void) 108void weird_irq(void)
285{ 109{
286 local_irq_disable(); 110 local_irq_disable();
@@ -288,10 +112,3 @@ void weird_irq(void)
288 while(1); 112 while(1);
289} 113}
290 114
291#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
292/* Used by other archs to show/control IRQ steering during SMP */
293void __init
294init_irq_proc(void)
295{
296}
297#endif