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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [ppc/] [kernel/] [irq.c] - Blame information for rev 1777

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

Line No. Rev Author Line
1 1624 jcastillo
/*
2
 *      linux/arch/ppc/kernel/irq.c
3
 *
4
 *      Copyright (C) 1992 Linus Torvalds
5
 *      Adapted from arch/i386 by Gary Thomas
6
 *
7
 * This file contains the code used by various IRQ handling routines:
8
 * asking for different IRQ's should be done through these routines
9
 * instead of just grabbing them. Thus setups with different IRQ numbers
10
 * shouldn't result in any weird surprises, and installing new handlers
11
 * should be easier.
12
 */
13
 
14
/*
15
 * IRQ's are in fact implemented a bit like signal handlers for the kernel.
16
 * Naturally it's not a 1:1 relation, but there are similarities.
17
 */
18
 
19
#include <linux/ptrace.h>
20
#include <linux/errno.h>
21
#include <linux/kernel_stat.h>
22
#include <linux/signal.h>
23
#include <linux/sched.h>
24
#include <linux/ioport.h>
25
#include <linux/interrupt.h>
26
#include <linux/timex.h>
27
 
28
#include <asm/system.h>
29
#include <asm/io.h>
30
#include <asm/irq.h>
31
#include <asm/bitops.h>
32
 
33
/*
34
 * For the BeBox, interrupt numbers are 0..15 for 8259 PIC interrupts
35
 * and 16..31 for other BeBox motherboard type interrupts.
36
 */
37
 
38
unsigned long isBeBox[];
39
unsigned char *BeBox_IO_page;
40
 
41
static unsigned char cache_21 = 0xff;
42
static unsigned char cache_A1 = 0xff;
43
 
44
void disable_irq(unsigned int irq_nr)
45
{
46
        unsigned char mask;
47
        int s = _disable_interrupts();
48
 
49
        if (isBeBox[0] && (irq_nr >= 16))
50
        {
51
                BeBox_disable_irq(irq_nr);
52
        } else
53
        {
54
                mask = 1 << (irq_nr & 7);
55
                if (irq_nr < 8) {
56
                        cache_21 |= mask;
57
                        outb(cache_21,0x21);
58
                } else
59
                {
60
                        cache_A1 |= mask;
61
                        outb(cache_A1,0xA1);
62
                }
63
        }
64
        _enable_interrupts(s);
65
}
66
 
67
void enable_irq(unsigned int irq_nr)
68
{
69
        unsigned char mask;
70
        int s = _disable_interrupts();
71
 
72
        if (isBeBox[0] && (irq_nr >= 16))
73
        {
74
                BeBox_enable_irq(irq_nr);
75
                _enable_interrupts(s);
76
                return;
77
        } else
78
        {
79
                mask = ~(1 << (irq_nr & 7));
80
                if (irq_nr < 8) {
81
                        cache_21 &= mask;
82
                        outb(cache_21,0x21);
83
                } else
84
                {
85
                        cache_A1 &= mask;
86
                        outb(cache_A1,0xA1);
87
                }
88
        }
89
        _enable_interrupts(s);
90
}
91
 
92
/*
93
 * Irq handlers.
94
 */
95
struct irq_action {
96
        void (*handler)(int, void *dev, struct pt_regs *);
97
        unsigned long flags;
98
        unsigned long mask;
99
        const char *name;
100
        int notified;
101
        void *dev_id;
102
};
103
 
104
static struct irq_action irq_action[32] = {
105
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
106
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
107
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
108
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
109
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
110
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
111
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
112
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
113
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
114
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
115
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
116
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
117
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
118
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
119
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
120
        { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
121
};
122
 
123
int get_irq_list(char *buf)
124
{
125
        int i, len = 0;
126
        struct irq_action * action = irq_action;
127
 
128
        for (i = 0;  i < 132;  i++, action++) {
129
                if (!action->handler)
130
                        continue;
131
                len += sprintf(buf+len, "%2d: %8d %c %s\n",
132
                        i, kstat.interrupts[i],
133
                        (action->flags & SA_INTERRUPT) ? '+' : ' ',
134
                        action->name);
135
        }
136
        return len;
137
}
138
 
139
asmlinkage void handle_IRQ(struct pt_regs *regs)
140
{
141
        int irq, _irq, s;
142
        struct irq_action *action;
143
        intr_count++;
144
        if (!isBeBox[0] || ((irq = BeBox_irq()) < 16))
145
        {
146
                /* Figure out IRQ#, etc. */
147
                outb(0x0C, 0x20);  /* Poll interrupt controller */
148
                irq = _irq = inb(0x20);
149
                irq &= 0x07;  /* Caution! */
150
                if (irq == 2)
151
                { /* Cascaded interrupt -> IRQ8..IRQ15 */
152
                        outb(0x0C, 0xA0);
153
                        irq = (_irq = inb(0xA0)) & 0x07;
154
                        irq += 8;
155
                }
156
                /* Mask interrupt & Issue EOI to interrupt controller */
157
                if (irq > 7)
158
                {
159
                        cache_A1 |= (1<<(irq-8));
160
                        outb(cache_A1, 0xA1);
161
#if 0                   
162
                        outb(0x20, 0xA0);
163
                        /* Need to ack cascade controller as well */
164
                        outb(0x20, 0x20);
165
#else                   
166
                        outb(0x60|(irq-8), 0xA0);       /* Specific EOI */
167
                        /* Need to ack cascade controller as well */
168
                        outb(0x62, 0x20);
169
#endif                  
170
                } else
171
                {
172
                        cache_21 |= (1<<irq);
173
                        outb(cache_21, 0x21);
174
                        outb(0x20, 0x20);
175
                }
176
        }
177
        action = irq + irq_action;
178
        kstat.interrupts[irq]++;
179
        if (action->handler)
180
        {
181
                action->handler(irq, action->dev_id, regs);
182
        } else
183
        {
184
                printk("Bogus interrupt #%d/%x, PC: %x\n", irq, _irq, regs->nip);
185
        }
186
        if (_disable_interrupts() && !action->notified)
187
        {
188
                action->notified = 1;
189
                printk("*** WARNING! %s handler [IRQ %d] turned interrupts on!\n", action->name, irq);
190
        }
191
        if (irq < 16)
192
        {
193
                if (!(action->flags & SA_ONESHOT))
194
                {
195
                        /* Re-enable interrupt */
196
                        if (irq > 7)
197
                        {
198
                                cache_A1 &= ~(1<<(irq-8));
199
                                outb(cache_A1, 0xA1);
200
                        } else
201
                        {
202
                                cache_21 &= ~(1<<irq);
203
                                outb(cache_21, 0x21);
204
                        }
205
                }
206
        } else
207
        {
208
                BeBox_enable_irq(irq);
209
        }
210
        intr_count--;
211
}
212
 
213
/*
214
 * This routine gets called when the SCSI times out on an operation.
215
 * I don't know why this happens, but every so often it does and it
216
 * seems to be a problem with the interrupt controller [state].  It
217
 * happens a lot when there is also network activity (both devices
218
 * are on the PCI bus with interrupts on the cascaded controller).
219
 * Re-initializing the interrupt controller [which might lose some
220
 * pending edge detected interrupts] seems to fix it.
221
 */
222
check_irq()
223
{
224
        int s;
225
        unsigned char _a0, _a1, _20, _21;
226
        if (isBeBox[0])
227
        {
228
                return;
229
        }
230
        s = _disable_interrupts();
231
        _a1 = inb(0xA1);
232
        _21 = inb(0x21);
233
        outb(0x0C, 0x20);  _20 = inb(0x20);
234
        outb(0x0C, 0xA0);  _a0 = inb(0xA0);
235
#if 0   
236
        printk("IRQ 0x20 = %x, 0x21 = %x/%x, 0xA0 = %x, 0xA1 = %x/%x\n",
237
                _20, _21, cache_21, _a0, _a1, cache_A1);
238
#endif          
239
        /* Reset interrupt controller - see if this fixes it! */
240
        /* Initialize interrupt controllers */
241
        outb(0x11, 0x20); /* Start init sequence */
242
        outb(0x40, 0x21); /* Vector base */
243
        outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */
244
        outb(0x01, 0x21); /* Select 8086 mode */
245
        outb(0xFF, 0x21); /* Mask all */
246
        outb(0x00, 0x4D0); /* All edge triggered */
247
        outb(0x11, 0xA0); /* Start init sequence */
248
        outb(0x48, 0xA1); /* Vector base */
249
        outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */
250
        outb(0x01, 0xA1); /* Select 8086 mode */
251
        outb(0xFF, 0xA1); /* Mask all */
252
        outb(0xCF, 0x4D1); /* Trigger mode */
253
        outb(cache_A1, 0xA1);
254
        outb(cache_21, 0x21);
255
        enable_irq(2);  /* Enable cascade interrupt */
256
        _enable_interrupts(s);
257
}
258
 
259
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
260
        unsigned long irqflags, const char * devname, void *dev_id)
261
{
262
        struct irq_action * action;
263
        unsigned long flags;
264
 
265
#if 0
266
_printk("Request IRQ #%d, Handler: %x\n", irq, handler);
267
#endif
268
        if (irq > 15)
269
        {
270
                if (!isBeBox[0] || (irq > 31))
271
                        return -EINVAL;
272
        }
273
        action = irq + irq_action;
274
        if (action->handler)
275
                return -EBUSY;
276
        if (!handler)
277
                return -EINVAL;
278
        save_flags(flags);
279
        cli();
280
        action->handler = handler;
281
        action->flags = irqflags;
282
        action->mask = 0;
283
        action->name = devname;
284
        action->dev_id = dev_id;
285
        enable_irq(irq);
286
        restore_flags(flags);
287
        return 0;
288
}
289
 
290
void free_irq(unsigned int irq, void *dev_id)
291
{
292
        struct irq_action * action = irq + irq_action;
293
        unsigned long flags;
294
 
295
        if (irq > 31) {
296
                printk("Trying to free IRQ%d\n",irq);
297
                return;
298
        }
299
        if (!action->handler) {
300
                printk("Trying to free free IRQ%d\n",irq);
301
                return;
302
        }
303
        disable_irq(irq);
304
        save_flags(flags);
305
        cli();
306
        action->handler = NULL;
307
        action->flags = 0;
308
        action->mask = 0;
309
        action->name = NULL;
310
        action->dev_id = NULL;
311
        restore_flags(flags);
312
}
313
 
314
#define SA_PROBE SA_ONESHOT
315
 
316
static void no_action(int irq, void *dev, struct pt_regs * regs)
317
{
318
#ifdef DEBUG
319
        printk("Probe got IRQ: %d\n", irq);
320
#endif
321
}
322
 
323
unsigned long probe_irq_on (void)
324
{
325
        unsigned int i, irqs = 0, irqmask;
326
        unsigned long delay;
327
 
328
        /* first, snaffle up any unassigned irqs */
329
        for (i = 15; i > 0; i--) {
330
                if (!request_irq(i, no_action, SA_PROBE, "probe", NULL)) {
331
                        enable_irq(i);
332
                        irqs |= (1 << i);
333
                }
334
        }
335
 
336
        /* wait for spurious interrupts to mask themselves out again */
337
        for (delay = jiffies + 2; delay > jiffies; );   /* min 10ms delay */
338
 
339
        /* now filter out any obviously spurious interrupts */
340
        irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
341
        for (i = 15; i > 0; i--) {
342
                if (irqs & (1 << i) & irqmask) {
343
                        irqs ^= (1 << i);
344
                        free_irq(i, NULL);
345
                }
346
        }
347
#ifdef DEBUG
348
        printk("probe_irq_on:  irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
349
#endif
350
        return irqs;
351
}
352
 
353
int probe_irq_off (unsigned long irqs)
354
{
355
        unsigned int i, irqmask;
356
 
357
        irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
358
        for (i = 15; i > 0; i--) {
359
                if (irqs & (1 << i)) {
360
                        free_irq(i, NULL);
361
                }
362
        }
363
#ifdef DEBUG
364
        printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
365
#endif
366
        irqs &= irqmask;
367
        if (!irqs)
368
                return 0;
369
        i = ffz(~irqs);
370
        if (irqs != (irqs & (1 << i)))
371
                i = -i;
372
        return i;
373
}
374
 
375
void init_IRQ(void)
376
{
377
        int i;
378
 
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
        if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
384
                printk("Unable to get IRQ2 for cascade\n");
385
        request_region(0x20,0x20,"pic1");
386
        request_region(0xa0,0x20,"pic2");
387
 
388
        /* Set up PCI interrupts */
389
        route_PCI_interrupts();
390
 
391
        if (isBeBox[0])
392
        {
393
                BeBox_init_IRQ();
394
        }
395
}
396
 
397
/*
398
 * Wrapper for "bottom 1/2" of interrupt processing.  This routine
399
 * is called whenever an interrupt needs non-interrupt-time service.
400
 */
401
 
402
_do_bottom_half()
403
{
404
        _enable_interrupts(1);
405
        do_bottom_half();
406
        _disable_interrupts();
407
}
408
 
409
 
410
/*
411
 * Support for interrupts on the BeBox
412
 */
413
 
414
#define CPU0_INT_MASK   (volatile unsigned long *)(BeBox_IO_page+0x0F0)
415
#define CPU1_INT_MASK   (volatile unsigned long *)(BeBox_IO_page+0x1F0)
416
#define INT_SOURCE      (volatile unsigned long *)(BeBox_IO_page+0x2F0)
417
#define CPU_RESET       (volatile unsigned long *)(BeBox_IO_page+0x4F0)
418
 
419
#define CPU_HRESET      0x20000000
420
#define CPU_SRESET      0x40000000
421
 
422
#define SCSI_IRQ        16
423
 
424
#define INT_SCSI        (1<<21)
425
#define INT_8259        (1<<5)
426
 
427
/*
428
 * Map of pseudo IRQs to actual bits
429
 * Note: We give out IRQ #16..31 for all interrupt sources which are
430
 * not found in the 8259 PIC.
431
 */
432
 
433
unsigned long BeBox_IRQ_map[] =
434
   {
435
        INT_SCSI,       /* 16 - SCSI */
436
        0x00000000,     /* 17 - Unused */
437
        0x00000000,     /* 18 - Unused */
438
        0x00000000,     /* 19 - Unused */
439
        0x00000000,     /* 20 - Unused */
440
        0x00000000,     /* 21 - Unused */
441
        0x00000000,     /* 22 - Unused */
442
        0x00000000,     /* 23 - Unused */
443
        0x00000000,     /* 24 - Unused */
444
        0x00000000,     /* 25 - Unused */
445
        0x00000000,     /* 26 - Unused */
446
        0x00000000,     /* 27 - Unused */
447
        0x00000000,     /* 28 - Unused */
448
        0x00000000,     /* 29 - Unused */
449
        0x00000000,     /* 30 - Unused */
450
        0x00000000,     /* 31 - Unused */
451
   };
452
 
453
volatile int CPU1_alive;
454
volatile int CPU1_trace;
455
 
456
static
457
_NOP()
458
{
459
}
460
 
461
static
462
_delay()
463
{
464
        int i;
465
        for (i = 0;  i < 100;  i++) _NOP();
466
}
467
 
468
void
469
BeBox_init_IRQ(void)
470
{
471
        int tmr;
472
        volatile extern long BeBox_CPU1_vector;
473
        *CPU0_INT_MASK = 0x0FFFFFFC;  /* Clear all bits? */
474
        *CPU0_INT_MASK = 0x80000003 | INT_8259;
475
        *CPU1_INT_MASK = 0x0FFFFFFC;
476
printk("Start CPU #1 - CPU Status: %x\n", *CPU_RESET);
477
        BeBox_CPU1_vector = 0x0100;  /* Reset */
478
        tmr = 0;
479
        while (CPU1_alive == 0)
480
        {
481
                if (++tmr == 1000)
482
                {
483
printk("CPU #1 not there? - CPU Status: %x, Trace: %x\n", *CPU_RESET, CPU1_trace);
484
                        break;
485
                }
486
                _delay();
487
        }
488
printk("CPU #1 running!\n");
489
#if 0
490
/* Temp - for SCSI */
491
        *(unsigned char *)0x81000038 = 0x00;
492
        *(unsigned char *)0x8080103C = 0xFF;
493
        *(unsigned char *)0x8080100D = 0x32;
494
#endif  
495
}
496
 
497
void
498
BeBox_disable_irq(int irq)
499
{
500
        /* Note: this clears the particular bit */
501
        *CPU0_INT_MASK = BeBox_IRQ_map[irq-16];
502
}
503
 
504
void
505
BeBox_enable_irq(int irq)
506
{
507
        int s = _disable_interrupts();
508
        /* Sets a single bit */
509
#if 0   
510
printk("BeBox IRQ Mask = %x", *CPU0_INT_MASK);
511
#endif
512
        *CPU0_INT_MASK = 0x80000000 | BeBox_IRQ_map[irq-16];
513
#if 0
514
printk("/%x\n", *CPU0_INT_MASK);
515
#endif  
516
        _enable_interrupts(s);
517
}
518
 
519
int
520
BeBox_irq(void)
521
{
522
        int i;
523
        unsigned long cpu0_int_mask;
524
        unsigned long int_state;
525
        cpu0_int_mask = (*CPU0_INT_MASK & 0x0FFFFFFC) & ~INT_8259;
526
        int_state = cpu0_int_mask & *INT_SOURCE;
527
        if (int_state)
528
        { /* Determine the pseudo-interrupt # */
529
#if 0   
530
                printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
531
#endif          
532
                for (i = 0;  i < 16;  i++)
533
                {
534
                        if (BeBox_IRQ_map[i] & int_state)
535
                        {
536
                                return (i+16);
537
                        }
538
                }
539
printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
540
printk("Can't find BeBox IRQ!\n");
541
        }
542
        return (0);
543
}
544
 
545
BeBox_state()
546
{
547
        printk("Int state = %x, CPU0 mask = %x, CPU1 mask = %x\n", *INT_SOURCE, *CPU0_INT_MASK, *CPU1_INT_MASK);
548
}
549
 
550
BeBox_CPU1()
551
{
552
        CPU1_alive++;
553
        while (1) ;
554
}

powered by: WebSVN 2.1.0

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