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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [mips/] [kernel/] [irq.c] - Blame information for rev 1775

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *      linux/arch/mips/kernel/irq.c
3
 *
4
 *      Copyright (C) 1992 Linus Torvalds
5
 *
6
 * This file contains the code used by various IRQ handling routines:
7
 * asking for different IRQ's should be done through these routines
8
 * instead of just grabbing them. Thus setups with different IRQ numbers
9
 * shouldn't result in any weird surprises, and installing new handlers
10
 * should be easier.
11
 */
12
 
13
/*
14
 * IRQ's are in fact implemented a bit like signal handlers for the kernel.
15
 * Naturally it's not a 1:1 relation, but there are similarities.
16
 */
17
 
18
/*
19
 * Mips support by Ralf Baechle and Andreas Busse
20
 *
21
 * The Deskstation Tyne is almost completely like an IBM compatible PC with
22
 * another type of microprocessor. Therefore this code is almost completely
23
 * the same. More work needs to be done to support Acer PICA and other
24
 * machines.
25
 */
26
 
27
#include <linux/ptrace.h>
28
#include <linux/errno.h>
29
#include <linux/kernel_stat.h>
30
#include <linux/signal.h>
31
#include <linux/sched.h>
32
#include <linux/types.h>
33
#include <linux/interrupt.h>
34
#include <linux/timex.h>
35
#include <linux/malloc.h>
36
#include <linux/random.h>
37
 
38
#include <asm/bitops.h>
39
#include <asm/bootinfo.h>
40
#include <asm/io.h>
41
#include <asm/irq.h>
42
#include <asm/jazz.h>
43
#include <asm/mipsregs.h>
44
#include <asm/system.h>
45
 
46
#define TIMER_IRQ 0                     /* Keep this in sync with time.c */
47
 
48
unsigned char cache_21 = 0xff;
49
unsigned char cache_A1 = 0xff;
50
 
51
unsigned long spurious_count = 0;
52
 
53
void disable_irq(unsigned int irq_nr)
54
{
55
        unsigned long flags;
56
        unsigned char mask;
57
 
58
        mask = 1 << (irq_nr & 7);
59
        save_flags(flags);
60
        if (irq_nr < 8) {
61
                cli();
62
                cache_21 |= mask;
63
                outb(cache_21,0x21);
64
                restore_flags(flags);
65
                return;
66
        }
67
        cli();
68
        cache_A1 |= mask;
69
        outb(cache_A1,0xA1);
70
        restore_flags(flags);
71
}
72
 
73
void enable_irq(unsigned int irq_nr)
74
{
75
        unsigned long flags;
76
        unsigned char mask;
77
 
78
        mask = ~(1 << (irq_nr & 7));
79
        save_flags(flags);
80
        if (irq_nr < 8) {
81
                cli();
82
                cache_21 &= mask;
83
                outb(cache_21,0x21);
84
                restore_flags(flags);
85
                return;
86
        }
87
        cli();
88
        cache_A1 &= mask;
89
        outb(cache_A1,0xA1);
90
        restore_flags(flags);
91
}
92
 
93
/*
94
 * Pointers to the low-level handlers: first the general ones, then the
95
 * fast ones, then the bad ones.
96
 */
97
extern void interrupt(void);
98
extern void fast_interrupt(void);
99
extern void bad_interrupt(void);
100
 
101
/*
102
 * Initial irq handlers.
103
 */
104
static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL};
105
static struct irqaction cascade_irq = { NULL, 0, 0, NULL, NULL, NULL};
106
static struct irqaction math_irq = { NULL, 0, 0, NULL, NULL, NULL};
107
 
108
static struct irqaction *irq_action[16] = {
109
          NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
110
          NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
111
};
112
 
113
int get_irq_list(char *buf)
114
{
115
        int i, len = 0;
116
        struct irqaction * action;
117
 
118
        for (i = 0 ; i < 16 ; i++) {
119
                action = *(i + irq_action);
120
                if (!action)
121
                        continue;
122
                len += sprintf(buf+len, "%2d: %8d %c %s",
123
                        i, kstat.interrupts[i],
124
                        (action->flags & SA_INTERRUPT) ? '+' : ' ',
125
                        action->name);
126
                for (action=action->next; action; action = action->next) {
127
                        len += sprintf(buf+len, ",%s %s",
128
                                (action->flags & SA_INTERRUPT) ? " +" : "",
129
                                action->name);
130
                }
131
                len += sprintf(buf+len, "\n");
132
        }
133
        return len;
134
}
135
 
136
/*
137
 * do_IRQ handles IRQ's that have been installed without the
138
 * SA_INTERRUPT flag: it uses the full signal-handling return
139
 * and runs with other interrupts enabled. All relatively slow
140
 * IRQ's should use this format: notably the keyboard/timer
141
 * routines.
142
 */
143
asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
144
{
145
        struct irqaction * action = *(irq + irq_action);
146
 
147
        kstat.interrupts[irq]++;
148
        if (action->flags & SA_SAMPLE_RANDOM)
149
                add_interrupt_randomness(irq);
150
        while (action) {
151
            action->handler(irq, action->dev_id, regs);
152
            action = action->next;
153
        }
154
}
155
 
156
/*
157
 * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
158
 * stuff - the handler is also running with interrupts disabled unless
159
 * it explicitly enables them later.
160
 */
161
asmlinkage void do_fast_IRQ(int irq)
162
{
163
        struct irqaction * action = *(irq + irq_action);
164
 
165
        kstat.interrupts[irq]++;
166
        if (action->flags & SA_SAMPLE_RANDOM)
167
                add_interrupt_randomness(irq);
168
        while (action) {
169
            action->handler(irq, action->dev_id, NULL);
170
            action = action->next;
171
        }
172
}
173
 
174
#define SA_PROBE SA_ONESHOT
175
 
176
int request_irq(unsigned int irq,
177
                void (*handler)(int, void *, struct pt_regs *),
178
                unsigned long irqflags,
179
                const char * devname,
180
                void *dev_id)
181
{
182
        struct irqaction * action, *tmp = NULL;
183
        unsigned long flags;
184
 
185
        if (irq > 15)
186
                return -EINVAL;
187
        if (!handler)
188
            return -EINVAL;
189
        action = *(irq + irq_action);
190
        if (action) {
191
            if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
192
                for (tmp = action; tmp->next; tmp = tmp->next);
193
            } else {
194
                return -EBUSY;
195
            }
196
            if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
197
              printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
198
              return -EBUSY;
199
            }
200
        }
201
        if (irqflags & SA_SAMPLE_RANDOM)
202
                rand_initialize_irq(irq);
203
        save_flags(flags);
204
        cli();
205
        if (irq == 2)
206
            action = &cascade_irq;
207
        else if (irq == 13)
208
          action = &math_irq;
209
        else if (irq == TIMER_IRQ)
210
          action = &timer_irq;
211
        else
212
          action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
213
 
214
        if (!action) {
215
            restore_flags(flags);
216
            return -ENOMEM;
217
        }
218
 
219
        action->handler = handler;
220
        action->flags = irqflags;
221
        action->mask = 0;
222
        action->name = devname;
223
        action->next = NULL;
224
        action->dev_id = dev_id;
225
 
226
        if (tmp) {
227
            tmp->next = action;
228
        } else {
229
            *(irq + irq_action) = action;
230
            if (!(action->flags & SA_PROBE)) {/* SA_ONESHOT used by probing */
231
                /*
232
                 * FIXME: Does the SA_INTERRUPT flag make any sense on MIPS???
233
                 */
234
                if (action->flags & SA_INTERRUPT)
235
                        set_int_vector(irq,fast_interrupt);
236
                else
237
                        set_int_vector(irq,interrupt);
238
            }
239
            if (irq < 8) {
240
                cache_21 &= ~(1<<irq);
241
                outb(cache_21,0x21);
242
            } else {
243
                cache_21 &= ~(1<<2);
244
                cache_A1 &= ~(1<<(irq-8));
245
                outb(cache_21,0x21);
246
                outb(cache_A1,0xA1);
247
            }
248
        }
249
        restore_flags(flags);
250
        return 0;
251
}
252
 
253
void free_irq(unsigned int irq, void *dev_id)
254
{
255
        struct irqaction * action = *(irq + irq_action);
256
        struct irqaction * tmp = NULL;
257
        unsigned long flags;
258
 
259
        if (irq > 15) {
260
                printk("Trying to free IRQ%d\n",irq);
261
                return;
262
        }
263
        if (!action->handler) {
264
                printk("Trying to free free IRQ%d\n",irq);
265
                return;
266
        }
267
        if (dev_id) {
268
            for (; action; action = action->next) {
269
                if (action->dev_id == dev_id) break;
270
                tmp = action;
271
            }
272
            if (!action) {
273
                printk("Trying to free free shared IRQ%d\n",irq);
274
                return;
275
            }
276
        } else if (action->flags & SA_SHIRQ) {
277
            printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
278
            return;
279
        }
280
        save_flags(flags);
281
        cli();
282
        if (action && tmp) {
283
            tmp->next = action->next;
284
        } else {
285
            *(irq + irq_action) = action->next;
286
        }
287
 
288
        if ((irq == 2) || (irq == 13) | (irq == TIMER_IRQ))
289
          memset(action, 0, sizeof(struct irqaction));
290
        else
291
          kfree_s(action, sizeof(struct irqaction));
292
 
293
        if (!(*(irq + irq_action))) {
294
            if (irq < 8) {
295
                cache_21 |= 1 << irq;
296
                outb(cache_21,0x21);
297
            } else {
298
                cache_A1 |= 1 << (irq-8);
299
                outb(cache_A1,0xA1);
300
            }
301
            set_int_vector(irq,bad_interrupt);
302
        }
303
        restore_flags(flags);
304
}
305
 
306
static void no_action(int cpl, void *dev_id, struct pt_regs * regs) { }
307
 
308
unsigned long probe_irq_on (void)
309
{
310
        unsigned int i, irqs = 0, irqmask;
311
        unsigned long delay;
312
 
313
        /* first, snaffle up any unassigned irqs */
314
        for (i = 15; i > 0; i--) {
315
                if (!request_irq(i, no_action, SA_PROBE, "probe", NULL)) {
316
                        enable_irq(i);
317
                        irqs |= (1 << i);
318
                }
319
        }
320
 
321
        /* wait for spurious interrupts to mask themselves out again */
322
        for (delay = jiffies + 2; delay > jiffies; );   /* min 10ms delay */
323
 
324
        /* now filter out any obviously spurious interrupts */
325
        irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
326
        for (i = 15; i > 0; i--) {
327
                if (irqs & (1 << i) & irqmask) {
328
                        irqs ^= (1 << i);
329
                        free_irq(i, NULL);
330
                }
331
        }
332
#ifdef DEBUG
333
        printk("probe_irq_on:  irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
334
#endif
335
        return irqs;
336
}
337
 
338
int probe_irq_off (unsigned long irqs)
339
{
340
        unsigned int i, irqmask;
341
 
342
        irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
343
        for (i = 15; i > 0; i--) {
344
                if (irqs & (1 << i)) {
345
                        free_irq(i, NULL);
346
                }
347
        }
348
#ifdef DEBUG
349
        printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
350
#endif
351
        irqs &= irqmask;
352
        if (!irqs)
353
                return 0;
354
        i = ffz(~irqs);
355
        if (irqs != (irqs & (1 << i)))
356
                i = -i;
357
        return i;
358
}
359
 
360
void init_IRQ(void)
361
{
362
        int i;
363
 
364
        switch (boot_info.machtype) {
365
                case MACH_MIPS_MAGNUM_4000:
366
                case MACH_ACER_PICA_61:
367
                        r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
368
                                          JAZZ_IE_ETHERNET |
369
                                          JAZZ_IE_SERIAL1  |
370
                                          JAZZ_IE_SERIAL2  |
371
                                          JAZZ_IE_PARALLEL |
372
                                          JAZZ_IE_FLOPPY);
373
                        r4030_read_reg16(JAZZ_IO_IRQ_SOURCE); /* clear pending IRQs */
374
                        set_cp0_status(ST0_IM, IE_IRQ4 | IE_IRQ1);
375
                        /* set the clock to 100 Hz */
376
                        r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9);
377
                        break;
378
                case MACH_DESKSTATION_TYNE:
379
                        /* set the clock to 100 Hz */
380
                        outb_p(0x34,0x43);              /* binary, mode 2, LSB/MSB, ch 0 */
381
                        outb_p(LATCH & 0xff , 0x40);    /* LSB */
382
                        outb(LATCH >> 8 , 0x40);        /* MSB */
383
 
384
                        if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
385
                                printk("Unable to get IRQ2 for cascade\n");
386
                        break;
387
                default:
388
                        panic("Unknown machtype in init_IRQ");
389
        }
390
 
391
        for (i = 0; i < 16 ; i++)
392
                set_int_vector(i, bad_interrupt);
393
 
394
        /* initialize the bottom half routines. */
395
        for (i = 0; i < 32; i++) {
396
                bh_base[i].routine = NULL;
397
                bh_base[i].data = NULL;
398
        }
399
        bh_active = 0;
400
        intr_count = 0;
401
}

powered by: WebSVN 2.1.0

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