Commit 2e0cea1decf7f21df0496571c218df3b3b8cce99

Authored by Mikael Starvik
Committed by Linus Torvalds
1 parent 63245d2cde

[PATCH] CRIS update: IRQ

Use the generic IRQ framework

Signed-off-by: Mikael Starvik <starvik@axis.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 6 changed files with 95 additions and 293 deletions Side-by-side Diff

arch/cris/arch-v10/kernel/irq.c
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 3 * linux/arch/cris/kernel/irq.c
4 4 *
5 5  
... ... @@ -12,11 +12,13 @@
12 12 */
13 13  
14 14 #include <asm/irq.h>
  15 +#include <linux/irq.h>
15 16 #include <linux/kernel.h>
16 17 #include <linux/init.h>
17 18 #include <linux/config.h>
18 19  
19   -irqvectptr 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 23 /* don't use set_int_vector, it bypasses the linux interrupt handlers. it is
22 24 * global just so that the kernel gdb can use it.
23 25  
24 26  
25 27  
26 28  
27 29  
28 30  
... ... @@ -102,41 +104,52 @@
102 104 IRQ31_interrupt
103 105 };
104 106  
105   -static void (*bad_interrupt[NR_IRQS])(void) = {
106   - NULL, NULL,
107   - NULL, bad_IRQ3_interrupt,
108   - bad_IRQ4_interrupt, bad_IRQ5_interrupt,
109   - bad_IRQ6_interrupt, bad_IRQ7_interrupt,
110   - bad_IRQ8_interrupt, bad_IRQ9_interrupt,
111   - bad_IRQ10_interrupt, bad_IRQ11_interrupt,
112   - bad_IRQ12_interrupt, bad_IRQ13_interrupt,
113   - NULL, NULL,
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   -};
  107 +static void enable_crisv10_irq(unsigned int irq);
122 108  
123   -void arch_setup_irq(int irq)
  109 +static unsigned int startup_crisv10_irq(unsigned int irq)
124 110 {
125   - set_int_vector(irq, interrupt[irq]);
  111 + enable_crisv10_irq(irq);
  112 + return 0;
126 113 }
127 114  
128   -void arch_free_irq(int irq)
  115 +#define shutdown_crisv10_irq disable_crisv10_irq
  116 +
  117 +static void enable_crisv10_irq(unsigned int irq)
129 118 {
130   - set_int_vector(irq, bad_interrupt[irq]);
  119 + unmask_irq(irq);
131 120 }
132 121  
  122 +static void disable_crisv10_irq(unsigned int irq)
  123 +{
  124 + mask_irq(irq);
  125 +}
  126 +
  127 +static void ack_crisv10_irq(unsigned int irq)
  128 +{
  129 +}
  130 +
  131 +static void end_crisv10_irq(unsigned int irq)
  132 +{
  133 +}
  134 +
  135 +static 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 +
133 146 void weird_irq(void);
134 147 void system_call(void); /* from entry.S */
135 148 void do_sigtrap(void); /* from entry.S */
136 149 void gdb_handle_breakpoint(void); /* from entry.S */
137 150  
138 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  
142 155 void __init
143 156  
... ... @@ -154,14 +167,15 @@
154 167  
155 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 170 for (i = 0; i < 256; i++)
163 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 179 /* the entries in the break vector contain actual code to be
166 180 executed by the associated break handler, rather than just a jump
167 181 address. therefore we need to setup a default breakpoint handler
... ... @@ -169,10 +183,6 @@
169 183  
170 184 for (i = 0; i < 16; i++)
171 185 set_break_vector(i, do_sigtrap);
172   -
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 186  
177 187 /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
178 188  
arch/cris/kernel/irq.c
... ... @@ -12,8 +12,6 @@
12 12 * shouldn't result in any weird surprises, and installing new handlers
13 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 22 #include <linux/config.h>
25 23 #include <linux/module.h>
26 24 #include <linux/ptrace.h>
  25 +#include <linux/irq.h>
27 26  
28 27 #include <linux/kernel_stat.h>
29 28 #include <linux/signal.h>
30 29  
31 30  
32 31  
33 32  
34 33  
35 34  
36 35  
37 36  
38 37  
... ... @@ -36,84 +35,56 @@
36 35 #include <linux/init.h>
37 36 #include <linux/seq_file.h>
38 37 #include <linux/errno.h>
39   -#include <linux/bitops.h>
  38 +#include <linux/spinlock.h>
40 39  
41 40 #include <asm/io.h>
42 41  
43   -/* Defined in arch specific irq.c */
44   -extern void arch_setup_irq(int irq);
45   -extern void arch_free_irq(int irq);
46   -
47   -void
48   -disable_irq(unsigned int irq_nr)
  42 +void ack_bad_irq(unsigned int irq)
49 43 {
50   - unsigned long flags;
51   -
52   - local_save_flags(flags);
53   - local_irq_disable();
54   - mask_irq(irq_nr);
55   - local_irq_restore(flags);
  44 + printk("unexpected IRQ trap at vector %02x\n", irq);
56 45 }
57 46  
58   -void
59   -enable_irq(unsigned int irq_nr)
60   -{
61   - unsigned long flags;
62   - local_save_flags(flags);
63   - local_irq_disable();
64   - unmask_irq(irq_nr);
65   - local_irq_restore(flags);
66   -}
67   -
68   -unsigned long
69   -probe_irq_on()
70   -{
71   - return 0;
72   -}
73   -
74   -EXPORT_SYMBOL(probe_irq_on);
75   -
76   -int
77   -probe_irq_off(unsigned long x)
78   -{
79   - return 0;
80   -}
81   -
82   -EXPORT_SYMBOL(probe_irq_off);
83   -
84   -/*
85   - * Initial irq handlers.
86   - */
87   -
88   -static struct irqaction *irq_action[NR_IRQS];
89   -
90 47 int show_interrupts(struct seq_file *p, void *v)
91 48 {
92   - int i = *(loff_t *) v;
  49 + int i = *(loff_t *) v, j;
93 50 struct irqaction * action;
94 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 61 if (i < NR_IRQS) {
97   - local_irq_save(flags);
98   - action = irq_action[i];
99   - if (!action)
  62 + spin_lock_irqsave(&irq_desc[i].lock, flags);
  63 + action = irq_desc[i].action;
  64 + if (!action)
100 65 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);
109   - }
  66 + seq_printf(p, "%3d: ",i);
  67 +#ifndef CONFIG_SMP
  68 + seq_printf(p, "%10u ", kstat_irqs(i));
  69 +#else
  70 + for (j = 0; j < NR_CPUS; j++)
  71 + if (cpu_online(j))
  72 + seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
  73 +#endif
  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 80 seq_putc(p, '\n');
111 81 skip:
112   - local_irq_restore(flags);
  82 + spin_unlock_irqrestore(&irq_desc[i].lock, flags);
113 83 }
114 84 return 0;
115 85 }
116 86  
  87 +
117 88 /* called by the assembler IRQ entry functions defined in irq.h
118 89 * to dispatch the interrupts to registred handlers
119 90 * interrupts are disabled upon entry - depending on if the
120 91  
121 92  
... ... @@ -123,176 +94,21 @@
123 94  
124 95 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
125 96 {
126   - struct irqaction *action;
127   - int do_random, cpu;
128   - int ret, retval = 0;
129   -
130   - cpu = smp_processor_id();
131   - irq_enter();
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   - }
  97 + unsigned long sp;
  98 + irq_enter();
  99 + sp = rdsp();
  100 + if (unlikely((sp & (PAGE_SIZE - 1)) < (PAGE_SIZE/8))) {
  101 + printk("do_IRQ: stack overflow: %lX\n", sp);
  102 + show_stack(NULL, (unsigned long *)sp);
  103 + }
  104 + __do_IRQ(irq, regs);
160 105 irq_exit();
161 106 }
162 107  
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   -
168   -int 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   -
220   -int 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   -
252   -EXPORT_SYMBOL(request_irq);
253   -
254   -void 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   - }
263   - for (p = irq - FIRST_IRQ + irq_action; (action = *p) != NULL; p = &action->next) {
264   - if (action->dev_id != dev_id)
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   -}
281   -
282   -EXPORT_SYMBOL(free_irq);
283   -
284 108 void weird_irq(void)
285 109 {
286 110 local_irq_disable();
287 111 printk("weird irq\n");
288 112 while(1);
289 113 }
290   -
291   -#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
292   -/* Used by other archs to show/control IRQ steering during SMP */
293   -void __init
294   -init_irq_proc(void)
295   -{
296   -}
297   -#endif
include/asm-cris/arch-v10/irq.h
... ... @@ -74,12 +74,9 @@
74 74 };
75 75  
76 76 extern struct etrax_interrupt_vector *etrax_irv;
77   -void set_int_vector(int n, irqvectptr addr, irqvectptr saddr);
  77 +void set_int_vector(int n, irqvectptr addr);
78 78 void set_break_vector(int n, irqvectptr addr);
79 79  
80   -#define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
81   -#define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
82   -
83 80 #define __STR(x) #x
84 81 #define STR(x) __STR(x)
85 82  
86 83  
87 84  
... ... @@ -121,26 +118,17 @@
121 118  
122 119 #define BUILD_IRQ(nr,mask) \
123 120 void IRQ_NAME(nr); \
124   -void sIRQ_NAME(nr); \
125   -void BAD_IRQ_NAME(nr); \
126 121 __asm__ ( \
127 122 ".text\n\t" \
128 123 "IRQ" #nr "_interrupt:\n\t" \
129 124 SAVE_ALL \
130   - "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \
131 125 BLOCK_IRQ(mask,nr) /* this must be done to prevent irq loops when we ei later */ \
132 126 "moveq "#nr",$r10\n\t" \
133 127 "move.d $sp,$r11\n\t" \
134 128 "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \
135 129 UNBLOCK_IRQ(mask) \
136 130 "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \
137   - "jump ret_from_intr\n\t" \
138   - "bad_IRQ" #nr "_interrupt:\n\t" \
139   - "push $r0\n\t" \
140   - BLOCK_IRQ(mask,nr) \
141   - "pop $r0\n\t" \
142   - "reti\n\t" \
143   - "nop\n");
  131 + "jump ret_from_intr\n\t");
144 132  
145 133 /* This is subtle. The timer interrupt is crucial and it should not be disabled for
146 134 * too long. However, if it had been a normal interrupt as per BUILD_IRQ, it would
147 135  
148 136  
... ... @@ -159,24 +147,15 @@
159 147  
160 148 #define BUILD_TIMER_IRQ(nr,mask) \
161 149 void IRQ_NAME(nr); \
162   -void sIRQ_NAME(nr); \
163   -void BAD_IRQ_NAME(nr); \
164 150 __asm__ ( \
165 151 ".text\n\t" \
166 152 "IRQ" #nr "_interrupt:\n\t" \
167 153 SAVE_ALL \
168   - "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \
169 154 "moveq "#nr",$r10\n\t" \
170 155 "move.d $sp,$r11\n\t" \
171 156 "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \
172 157 "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \
173   - "jump ret_from_intr\n\t" \
174   - "bad_IRQ" #nr "_interrupt:\n\t" \
175   - "push $r0\n\t" \
176   - BLOCK_IRQ(mask,nr) \
177   - "pop $r0\n\t" \
178   - "reti\n\t" \
179   - "nop\n");
  158 + "jump ret_from_intr\n\t");
180 159  
181 160 #endif
include/asm-cris/hardirq.h
1 1 #ifndef __ASM_HARDIRQ_H
2 2 #define __ASM_HARDIRQ_H
3 3  
4   -/* only non-SMP supported */
5   -
6 4 #include <linux/threads.h>
7 5 #include <linux/cache.h>
8 6  
9   -/* entry.S is sensitive to the offsets of these fields */
10 7 typedef struct {
11 8 unsigned int __softirq_pending;
12 9 } ____cacheline_aligned irq_cpustat_t;
13 10  
14 11 #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
  12 +
  13 +void ack_bad_irq(unsigned int irq);
15 14  
16 15 #define HARDIRQ_BITS 8
17 16  
include/asm-cris/hw_irq.h
  1 +#ifndef _ASM_HW_IRQ_H
  2 +#define _ASM_HW_IRQ_H
  3 +
  4 +static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
  5 +
  6 +#endif
include/asm-cris/irq.h
... ... @@ -8,15 +8,5 @@
8 8 return irq;
9 9 }
10 10  
11   -extern void disable_irq(unsigned int);
12   -extern void enable_irq(unsigned int);
13   -
14   -#define disable_irq_nosync disable_irq
15   -#define enable_irq_nosync enable_irq
16   -
17   -struct irqaction;
18   -struct pt_regs;
19   -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
20   -
21 11 #endif /* _ASM_IRQ_H */