OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [cris/] [kernel/] [irq.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      linux/arch/cris/kernel/irq.c
3
 *
4
 *      Copyright (c) 2000, 2001, 2002, 2003 Axis Communications AB
5
 *
6
 *      Authors: Bjorn Wesen (bjornw@axis.com)
7
 *
8
 * This file contains the code used by various IRQ handling routines:
9
 * asking for different IRQ's should be done through these routines
10
 * instead of just grabbing them. Thus setups with different IRQ numbers
11
 * shouldn't result in any weird surprises, and installing new handlers
12
 * should be easier.
13
 *
14
 * Notice Linux/CRIS: these routines do not care about SMP
15
 *
16
 */
17
 
18
/*
19
 * IRQ's are in fact implemented a bit like signal handlers for the kernel.
20
 * Naturally it's not a 1:1 relation, but there are similarities.
21
 */
22
 
23
#include <linux/config.h>
24
#include <linux/ptrace.h>
25
#include <linux/errno.h>
26
#include <linux/kernel_stat.h>
27
#include <linux/signal.h>
28
#include <linux/sched.h>
29
#include <linux/ioport.h>
30
#include <linux/interrupt.h>
31
#include <linux/timex.h>
32
#include <linux/slab.h>
33
#include <linux/random.h>
34
#include <linux/init.h>
35
 
36
#include <asm/system.h>
37
#include <asm/io.h>
38
#include <asm/irq.h>
39
#include <asm/bitops.h>
40
 
41
#include <asm/svinto.h>
42
 
43
char *hw_bp_msg = "BP 0x%x\n";
44
 
45
static inline void
46
mask_irq(unsigned int irq_nr)
47
{
48
        *R_VECT_MASK_CLR = 1 << irq_nr;
49
}
50
 
51
static inline void
52
unmask_irq(unsigned int irq_nr)
53
{
54
        *R_VECT_MASK_SET = 1 << irq_nr;
55
}
56
 
57
void
58
disable_irq(unsigned int irq_nr)
59
{
60
        unsigned long flags;
61
 
62
        save_flags(flags);
63
        cli();
64
        mask_irq(irq_nr);
65
        restore_flags(flags);
66
}
67
 
68
void
69
enable_irq(unsigned int irq_nr)
70
{
71
        unsigned long flags;
72
 
73
        save_flags(flags);
74
        cli();
75
        unmask_irq(irq_nr);
76
        restore_flags(flags);
77
}
78
 
79
unsigned long
80
probe_irq_on()
81
{
82
        return 0;
83
}
84
 
85
int
86
probe_irq_off(unsigned long x)
87
{
88
        return 0;
89
}
90
 
91
/* vector of shortcut jumps after the irq prologue */
92
irqvectptr irq_shortcuts[NR_IRQS];
93
 
94
/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is
95
 * global just so that the kernel gdb can use it.
96
 */
97
 
98
void
99
set_int_vector(int n, irqvectptr addr, irqvectptr saddr)
100
{
101
        /* remember the shortcut entry point, after the prologue */
102
 
103
        irq_shortcuts[n] = saddr;
104
 
105
        etrax_irv->v[n + 0x20] = (irqvectptr)addr;
106
}
107
 
108
/* the breakpoint vector is obviously not made just like the normal irq
109
 * handlers but needs to contain _code_ to jump to addr.
110
 *
111
 * the BREAK n instruction jumps to IBR + n * 8
112
 */
113
 
114
void
115
set_break_vector(int n, irqvectptr addr)
116
{
117
        unsigned short *jinstr = (unsigned short *)&etrax_irv->v[n*2];
118
        unsigned long *jaddr = (unsigned long *)(jinstr + 1);
119
 
120
        /* if you don't know what this does, do not touch it! */
121
 
122
        *jinstr = 0x0d3f;
123
        *jaddr = (unsigned long)addr;
124
 
125
        /* 00000026 <clrlop+1a> 3f0d82000000     jump  0x82 */
126
}
127
 
128
 
129
/*
130
 * This builds up the IRQ handler stubs using some ugly macros in irq.h
131
 *
132
 * These macros create the low-level assembly IRQ routines that do all
133
 * the operations that are needed. They are also written to be fast - and to
134
 * disable interrupts as little as humanly possible.
135
 *
136
 */
137
 
138
/* IRQ0 and 1 are special traps */
139
void hwbreakpoint(void);
140
void IRQ1_interrupt(void);
141
BUILD_TIMER_IRQ(2, 0x04)       /* the timer interrupt is somewhat special */
142
BUILD_IRQ(3, 0x08)
143
BUILD_IRQ(4, 0x10)
144
BUILD_IRQ(5, 0x20)
145
BUILD_IRQ(6, 0x40)
146
BUILD_IRQ(7, 0x80)
147
BUILD_IRQ(8, 0x100)
148
BUILD_IRQ(9, 0x200)
149
BUILD_IRQ(10, 0x400)
150
BUILD_IRQ(11, 0x800)
151
BUILD_IRQ(12, 0x1000)
152
BUILD_IRQ(13, 0x2000)
153
void mmu_bus_fault(void);      /* IRQ 14 is the bus fault interrupt */
154
void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */
155
BUILD_IRQ(16, 0x10000)
156
BUILD_IRQ(17, 0x20000)
157
BUILD_IRQ(18, 0x40000)
158
BUILD_IRQ(19, 0x80000)
159
BUILD_IRQ(20, 0x100000)
160
BUILD_IRQ(21, 0x200000)
161
BUILD_IRQ(22, 0x400000)
162
BUILD_IRQ(23, 0x800000)
163
BUILD_IRQ(24, 0x1000000)
164
BUILD_IRQ(25, 0x2000000)
165
/* IRQ 26-30 are reserved */
166
BUILD_IRQ(31, 0x80000000)
167
 
168
/*
169
 * Pointers to the low-level handlers
170
 */
171
 
172
static void (*interrupt[NR_IRQS])(void) = {
173
        NULL, NULL, IRQ2_interrupt, IRQ3_interrupt,
174
        IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
175
        IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt,
176
        IRQ12_interrupt, IRQ13_interrupt, NULL, NULL,
177
        IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt,
178
        IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt,
179
        IRQ24_interrupt, IRQ25_interrupt, NULL, NULL, NULL, NULL, NULL,
180
        IRQ31_interrupt
181
};
182
 
183
static void (*sinterrupt[NR_IRQS])(void) = {
184
        NULL, NULL, sIRQ2_interrupt, sIRQ3_interrupt,
185
        sIRQ4_interrupt, sIRQ5_interrupt, sIRQ6_interrupt, sIRQ7_interrupt,
186
        sIRQ8_interrupt, sIRQ9_interrupt, sIRQ10_interrupt, sIRQ11_interrupt,
187
        sIRQ12_interrupt, sIRQ13_interrupt, NULL, NULL,
188
        sIRQ16_interrupt, sIRQ17_interrupt, sIRQ18_interrupt, sIRQ19_interrupt,
189
        sIRQ20_interrupt, sIRQ21_interrupt, sIRQ22_interrupt, sIRQ23_interrupt,
190
        sIRQ24_interrupt, sIRQ25_interrupt, NULL, NULL, NULL, NULL, NULL,
191
        sIRQ31_interrupt
192
};
193
 
194
static void (*bad_interrupt[NR_IRQS])(void) = {
195
        NULL, NULL,
196
        NULL, bad_IRQ3_interrupt,
197
        bad_IRQ4_interrupt, bad_IRQ5_interrupt,
198
        bad_IRQ6_interrupt, bad_IRQ7_interrupt,
199
        bad_IRQ8_interrupt, bad_IRQ9_interrupt,
200
        bad_IRQ10_interrupt, bad_IRQ11_interrupt,
201
        bad_IRQ12_interrupt, bad_IRQ13_interrupt,
202
        NULL, NULL,
203
        bad_IRQ16_interrupt, bad_IRQ17_interrupt,
204
        bad_IRQ18_interrupt, bad_IRQ19_interrupt,
205
        bad_IRQ20_interrupt, bad_IRQ21_interrupt,
206
        bad_IRQ22_interrupt, bad_IRQ23_interrupt,
207
        bad_IRQ24_interrupt, bad_IRQ25_interrupt,
208
        NULL, NULL, NULL, NULL, NULL,
209
        bad_IRQ31_interrupt
210
};
211
 
212
/*
213
 * Initial irq handlers.
214
 */
215
 
216
static struct irqaction *irq_action[NR_IRQS] = {
217
        NULL, NULL, NULL, NULL,
218
        NULL, NULL, NULL, NULL,
219
        NULL, NULL, NULL, NULL,
220
        NULL, NULL, NULL, NULL,
221
        NULL, NULL, NULL, NULL,
222
        NULL, NULL, NULL, NULL,
223
        NULL, NULL, NULL, NULL,
224
        NULL, NULL, NULL, NULL
225
};
226
 
227
int get_irq_list(char *buf)
228
{
229
        int i, len = 0;
230
        struct irqaction * action;
231
 
232
        for (i = 0; i < NR_IRQS; i++) {
233
                action = irq_action[i];
234
                if (!action)
235
                        continue;
236
                len += sprintf(buf+len, "%2d: %10u %c %s",
237
                        i, kstat.irqs[0][i],
238
                        (action->flags & SA_INTERRUPT) ? '+' : ' ',
239
                        action->name);
240
                for (action = action->next; action; action = action->next) {
241
                        len += sprintf(buf+len, ",%s %s",
242
                                (action->flags & SA_INTERRUPT) ? " +" : "",
243
                                action->name);
244
                }
245
                len += sprintf(buf+len, "\n");
246
        }
247
        return len;
248
}
249
 
250
/* called by the assembler IRQ entry functions defined in irq.h
251
 * to dispatch the interrupts to registred handlers
252
 * interrupts are disabled upon entry - depending on if the
253
 * interrupt was registred with SA_INTERRUPT or not, interrupts
254
 * are re-enabled or not.
255
 */
256
 
257
asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
258
{
259
        struct irqaction *action;
260
        int do_random, cpu;
261
 
262
        cpu = smp_processor_id();
263
        irq_enter(cpu);
264
        kstat.irqs[cpu][irq]++;
265
 
266
        action = irq_action[irq];
267
        if (action) {
268
                if (!(action->flags & SA_INTERRUPT))
269
                        __sti();
270
                action = irq_action[irq];
271
                do_random = 0;
272
                do {
273
                        do_random |= action->flags;
274
                        action->handler(irq, action->dev_id, regs);
275
                        action = action->next;
276
                } while (action);
277
                if (do_random & SA_SAMPLE_RANDOM)
278
                        add_interrupt_randomness(irq);
279
                __cli();
280
        }
281
        irq_exit(cpu);
282
 
283
        if (softirq_pending(cpu))
284
                do_softirq();
285
 
286
        /* unmasking and bottom half handling is done magically for us. */
287
}
288
 
289
/* this function links in a handler into the chain of handlers for the
290
 * given irq, and if the irq has never been registred, the appropriate
291
 * handler is entered into the interrupt vector
292
 */
293
 
294
int setup_etrax_irq(int irq, struct irqaction * new)
295
{
296
        int shared = 0;
297
        struct irqaction *old, **p;
298
        unsigned long flags;
299
 
300
        p = irq_action + irq;
301
        if ((old = *p) != NULL) {
302
                /* Can't share interrupts unless both agree to */
303
                if (!(old->flags & new->flags & SA_SHIRQ))
304
                        return -EBUSY;
305
 
306
                /* Can't share interrupts unless both are same type */
307
                if ((old->flags ^ new->flags) & SA_INTERRUPT)
308
                        return -EBUSY;
309
 
310
                /* add new interrupt at end of irq queue */
311
                do {
312
                        p = &old->next;
313
                        old = *p;
314
                } while (old);
315
                shared = 1;
316
        }
317
 
318
        if (new->flags & SA_SAMPLE_RANDOM)
319
                rand_initialize_irq(irq);
320
 
321
        save_flags(flags);
322
        cli();
323
        *p = new;
324
 
325
        if (!shared) {
326
                /* if the irq wasn't registred before, enter it into the vector
327
                 * table and unmask it physically
328
                 */
329
                set_int_vector(irq, interrupt[irq], sinterrupt[irq]);
330
                unmask_irq(irq);
331
        }
332
 
333
        restore_flags(flags);
334
        return 0;
335
}
336
 
337
/* this function is called by a driver to register an irq handler
338
 * Valid flags:
339
 *   SA_INTERRUPT: it's a fast interrupt, handler called with irq disabled and
340
 *                 no signal checking etc is performed upon exit
341
 *   SA_SHIRQ:     the interrupt can be shared between different handlers, the
342
 *                 handler is required to check if the irq was "aimed" at it
343
 *                 explicitely
344
 *   SA_RANDOM:    the interrupt will add to the random generators entropy
345
 */
346
 
347
int request_irq(unsigned int irq,
348
                void (*handler)(int, void *, struct pt_regs *),
349
                unsigned long irqflags,
350
                const char * devname,
351
                void *dev_id)
352
{
353
        int retval;
354
        struct irqaction * action;
355
 
356
        /* interrupts 0 and 1 are hardware breakpoint and NMI and we can't
357
         * support these yet. interrupt 15 is the multiple irq, it's special.
358
         */
359
 
360
        if(irq < 2 || irq == 15 || irq >= NR_IRQS)
361
                return -EINVAL;
362
 
363
        if(!handler)
364
                return -EINVAL;
365
 
366
        /* allocate and fill in a handler structure and setup the irq */
367
 
368
        action = kmalloc(sizeof *action, GFP_KERNEL);
369
        if (!action)
370
                return -ENOMEM;
371
 
372
        action->handler = handler;
373
        action->flags = irqflags;
374
        action->mask = 0;
375
        action->name = devname;
376
        action->next = NULL;
377
        action->dev_id = dev_id;
378
 
379
        retval = setup_etrax_irq(irq, action);
380
 
381
        if (retval)
382
                kfree(action);
383
        return retval;
384
}
385
 
386
void free_irq(unsigned int irq, void *dev_id)
387
{
388
        struct irqaction * action, **p;
389
        unsigned long flags;
390
 
391
        if (irq >= NR_IRQS) {
392
                printk("Trying to free IRQ%d\n",irq);
393
                return;
394
        }
395
        for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
396
                if (action->dev_id != dev_id)
397
                        continue;
398
 
399
                /* Found it - now free it */
400
                save_flags(flags);
401
                cli();
402
                *p = action->next;
403
                if (!irq_action[irq]) {
404
                        mask_irq(irq);
405
                        set_int_vector(irq, bad_interrupt[irq], 0);
406
                }
407
                restore_flags(flags);
408
                kfree(action);
409
                return;
410
        }
411
        printk("Trying to free free IRQ%d\n",irq);
412
}
413
 
414
void weird_irq(void)
415
{
416
        __asm__("di");
417
        printk("weird irq\n");
418
        while(1);
419
}
420
 
421
/* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks
422
 * and setting the irq vector table to point to bad_interrupt ptrs.
423
 */
424
 
425
void system_call(void);  /* from entry.S */
426
void do_sigtrap(void); /* from entry.S */
427
void gdb_handle_breakpoint(void); /* from entry.S */
428
 
429
void __init
430
init_IRQ(void)
431
{
432
        int i;
433
 
434
        /* clear all interrupt masks */
435
 
436
#ifndef CONFIG_SVINTO_SIM
437
        *R_IRQ_MASK0_CLR = 0xffffffff;
438
        *R_IRQ_MASK1_CLR = 0xffffffff;
439
        *R_IRQ_MASK2_CLR = 0xffffffff;
440
#endif
441
 
442
        *R_VECT_MASK_CLR = 0xffffffff;
443
 
444
        /* clear the shortcut entry points */
445
 
446
        for(i = 0; i < NR_IRQS; i++)
447
                irq_shortcuts[i] = NULL;
448
 
449
        for (i = 0; i < 256; i++)
450
                etrax_irv->v[i] = weird_irq;
451
 
452
        /* the entries in the break vector contain actual code to be
453
         * executed by the associated break handler, rather than just a jump
454
         * address. therefore we need to setup a default breakpoint handler
455
         * for all breakpoints
456
         */
457
 
458
        for (i = 0; i < 16; i++)
459
                set_break_vector(i, do_sigtrap);
460
 
461
        /* set all etrax irq's to the bad handlers */
462
        for (i = 2; i < NR_IRQS; i++)
463
                set_int_vector(i, bad_interrupt[i], 0);
464
 
465
        /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
466
 
467
        set_int_vector(15, multiple_interrupt, 0);
468
 
469
        /* 0 and 1 which are special breakpoint/NMI traps */
470
 
471
        set_int_vector(0, hwbreakpoint, 0);
472
        set_int_vector(1, IRQ1_interrupt, 0);
473
 
474
        /* and irq 14 which is the mmu bus fault handler */
475
 
476
        set_int_vector(14, mmu_bus_fault, 0);
477
 
478
        /* setup the system-call trap, which is reached by BREAK 13 */
479
 
480
        set_break_vector(13, system_call);
481
 
482
        /* setup a breakpoint handler for debugging used for both user and
483
         * kernel mode debugging  (which is why it is not inside an ifdef
484
         * CONFIG_ETRAX_KGDB)
485
         */
486
        set_break_vector(8, gdb_handle_breakpoint);
487
 
488
#ifdef CONFIG_ETRAX_KGDB
489
        /* setup kgdb if its enabled, and break into the debugger */
490
        kgdb_init();
491
        breakpoint();
492
#endif
493
}
494
 
495
#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
496
/* Used by other archs to show/control IRQ steering during SMP */
497
void __init
498
init_irq_proc(void)
499
{
500
}
501
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.