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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [i960/] [kernel/] [ints.c] - Blame information for rev 199

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

Line No. Rev Author Line
1 199 simons
/*
2
 * linux/arch/i960/kernel/ints.c
3
 *
4
 * Copyright (C) 1999   Keith Adams     <kma@cse.ogi.edu>
5
 *                      Oregon Graduate Institute
6
 *
7
 * Based on:
8
 *
9
 * linux/arch/i386/kernel/irq.c
10
 *
11
 * Copyright (C) 1992 Linux Torvalds
12
 *
13
 * This file is subject to the terms and conditions of the GNU General Public
14
 * License.  See the file COPYING in the main directory of this archive
15
 * for more details.
16
 *
17
 * N.B. that we treat "irq" as meaning, the high order four bits of the vector
18
 * number. Since there seems to be no way to set the low bits to something other
19
 * than 0010, this is good enough for us.
20
 */
21
 
22
#include <linux/types.h>
23
#include <linux/sched.h>
24
#include <linux/kernel_stat.h>
25
#include <linux/errno.h>
26
#include <linux/interrupt.h>
27
#include <linux/config.h>
28
#include <linux/ip.h>
29
#include <linux/tcp.h>
30
 
31
#include <asm/atomic.h>
32
#include <asm/system.h>
33
#include <asm/irq.h>
34
#include <asm/traps.h>
35
#include <asm/page.h>
36
#include <asm/ptrace.h>
37
#include <asm/machdep.h>
38
#include <asm/i960.h>
39
#include <asm/unistd.h>
40
 
41
#if defined(CONFIG_I960JX) || defined(CONFIG_I960VH)
42
#include <asm/i960jx.h>
43
#endif
44
 
45
/*
46
 * device vectors; the *_HO macros are the corresponding indices into the
47
 * low-mem isr table
48
 */
49
#define NMI_VEC         248
50
 
51
#define LED     ((unsigned char*)0xe0040000)
52
#define LED_THRESHOLD   (HZ/2)
53
 
54
#define TMR0_VEC_HO 0xd
55
#define TMR1_VEC_HO 0xe
56
#define XINT0_VEC_HO 1
57
#define XINT1_VEC_HO 2
58
#define XINT2_VEC_HO 3
59
#define XINT3_VEC_HO 4
60
#define XINT4_VEC_HO 5
61
#define XINT5_VEC_HO 6
62
#define XINT6_VEC_HO 7
63
#define XINT7_VEC_HO 8
64
 
65
static char* irq_names[] = {
66
        0,       /* 0 */
67
        "xint0",
68
        "xint1",
69
        "xint2",
70
        "xint3",
71
        "serial",
72
        "xint5",
73
        "xint6",
74
        "xint7",
75
        0, 0, 0, 0,
76
        "timer0",
77
        "timer1",
78
        0,
79
};
80
 
81
#ifdef CONFIG_PROF_IRQ
82
static struct irqstat {
83
        unsigned long   min;
84
        unsigned long   avg;
85
        unsigned long   max;
86
} irqstat[16];
87
#endif
88
 
89
static void* pci_dev;
90
static const char* pci_name;
91
static void (*pci_isr)(int, void *, struct pt_regs *);
92
 
93
#define __VEC(ho)       (((ho) << 4) | 2)
94
#define TMR0_VEC __VEC(TMR0_VEC_HO)
95
#define TMR1_VEC __VEC(TMR1_VEC_HO)
96
#define XINT0_VEC __VEC(XINT0_VEC_HO)
97
#define XINT1_VEC __VEC(XINT1_VEC_HO)
98
#define XINT2_VEC __VEC(XINT2_VEC_HO)
99
#define XINT3_VEC __VEC(XINT3_VEC_HO)
100
#define XINT4_VEC __VEC(XINT4_VEC_HO)
101
#define SERIAL_VEC XINT4_VEC
102
#define PCI_VEC XINT1_VEC
103
#define XINT5_VEC __VEC(XINT5_VEC_HO)
104
#define XINT6_VEC __VEC(XINT6_VEC_HO)
105
#define XINT7_VEC __VEC(XINT7_VEC_HO)
106
 
107
 
108
void leave_kernel(struct pt_regs* regs);
109
static void nmi_intr(void);
110
static void bad_intr(unsigned char vec, struct pt_regs* regs);
111
static void xint(unsigned char ho, struct pt_regs* regs);
112
void stack_trace(void);
113
 
114
extern void intr(void);
115
static void program_clock(void);
116
 
117
#ifdef CONFIG_MON960
118
#include <asm/i960jx.h>
119
#include <asm/mon960.h>
120
 
121
static unsigned long get_mon960_serial_isr(void)
122
{
123
        prcb_t* prcb = (prcb_t*)get_prcbptr();
124
        unsigned long vec = (*(unsigned long*)IMAP1 & 0x0f00) >> 8;
125
 
126
        /* on cyclone, serial isr is XINT5 */
127
        return (unsigned long) prcb->pr_intr_tab->i_vectors[vec];
128
}
129
 
130
#endif
131
 
132
static void init_syscalls(void)
133
{
134
        unsigned long** prcb = (unsigned long**)get_prcbptr();
135
        unsigned long* syscall_tab = prcb[5];
136
        extern void syscall(void);
137
        /* we only use syscall 0, which is 12 words from the start of
138
         * the syscall table. The entry type field of 0x2 indicates a call
139
         * to supervisor mode.  */
140
        syscall_tab[12] = ((unsigned long) syscall) | 0x2;
141
        return;
142
}
143
 
144
/*
145
 * At entry here, we have a high ipl. We need to establish
146
 * our isr's, and enable the clock.
147
 */
148
void init_IRQ(void)
149
{
150
        unsigned long   *dram = 0;
151
        int     ii;
152
 
153
        /* set up the following layout in low RAM for our 15 vectors:
154
         * 0:           NMI (we have no choice about this)
155
         * 1-8:         XINT0-7
156
         * 9-12:        Invalid
157
         * 13:          Timer0. Note that Timer1 is disabled.
158
         * 14-15:       Invalid.
159
         *
160
         * This works out nicely, since the vector number-1 is the
161
         * corresponding bit in IMSK; see disable_irq below.
162
         */
163
        atmod((void*)IMAP0, 0xffff, 0x4321);            /* xint 0-3 */
164
        atmod((void*)IMAP1, 0xffff, 0x8756);            /* xint 4-7 */
165
        atmod((void*)IMAP2, 0xff<<16, 0xed << 16);      /* Timer 0, Timer 1 */
166
 
167
        /* we vector all interrupts through intr */
168
        for (ii=0; ii < 16; ii++)
169
                dram[ii] = (unsigned long)intr;
170
 
171
#ifdef CONFIG_MON960
172
        /* reset the XINT5 interrupt handler from software */
173
        dram[XINT5_VEC_HO] = get_mon960_serial_isr();
174
#endif
175
 
176
        program_clock();
177
        /* set 13th bit of ICON; enable vector caching */
178
        atmod((void*)ICON, 1<<13, 1<<13);
179
        /*
180
         * XXX: what to mask is somewhat board dependent; we leave XINT4
181
         * masked because Cyclone needs it to always be masked.
182
         */
183
        atmod((void*)IPND, ~0, 0);
184
        atmod((void*)IMSK, 0x30ef, 0x30ef);
185
 
186
        /* Now set up syscalls */
187
        init_syscalls();
188
}
189
 
190
#define TRR0    (volatile unsigned long*)0xff000300
191
#define TCR0    (volatile unsigned long*)0xff000304
192
#define TMR0    (volatile unsigned long*)0xff000308
193
 
194
#define TRR1    (volatile unsigned long*)0xff000310
195
#define TCR1    (volatile unsigned long*)0xff000314
196
#define TMR1    (volatile unsigned long*)0xff000318
197
/* some helper macros for programming the mode register, TMR0 */
198
 
199
/* the clock may decrement once per cpu cycle, once every two cycles, ...
200
 * up to eight; set the appropriate bits in TMR0
201
 */
202
#define CLOCKSHIFT 4
203
#define CLOCKDIV(x)     (x << CLOCKSHIFT)
204
#define CLOCKDIV1 CLOCKDIV(0)
205
#define CLOCKDIV2 CLOCKDIV(1)
206
#define CLOCKDIV4 CLOCKDIV(2)
207
#define CLOCKDIV8 CLOCKDIV(3)
208
 
209
#define CLOCK_ENABLE            2       /* set for clock to work */
210
#define CLOCK_AUTO_RELOAD       4       /* reload from TRR0 when we reach 0 */
211
#define CLOCK_SUPER_ONLY        8       /* don't let users reprogram clocks */
212
 
213
/*
214
 * Set up timer 0 to interrupt us every so many clocks. Assumes
215
 * interrupts are disabled.
216
 */
217
static void
218
program_clock(void)
219
{
220
        /* 33Mhz PCI Bus assumed */
221
#define CYCLES_PER_HZ   (33 * 1000* 1000) / HZ
222
        *TRR0 = *TCR0 = CYCLES_PER_HZ;
223
        *TMR0 = CLOCKDIV1 | CLOCK_ENABLE | CLOCK_AUTO_RELOAD | CLOCK_SUPER_ONLY;
224
 
225
#ifdef CONFIG_PROF_IRQ
226
        disable_irq(TMR1_VEC_HO);
227
#endif
228
}
229
 
230
irq_node_t *new_irq_node(void)
231
{
232
        /* XXX: write me */
233
        return NULL;
234
}
235
 
236
int request_irq(unsigned int irq,
237
                void (*handler)(int, void *, struct pt_regs *),
238
                unsigned long flags, const char *devname, void *dev_id)
239
{
240
        /* XXX: this is a stopgap; we only can handle one pci device */
241
        if (pci_dev)
242
                return -1;
243
 
244
        pci_dev = dev_id;
245
        pci_name = devname;
246
        pci_isr = handler;
247
        return 0;
248
}
249
 
250
void free_irq(unsigned int irq, void *dev_id)
251
{
252
        pci_dev = 0;
253
}
254
 
255
/*
256
 * Do we need these probe functions on the i960?
257
 */
258
unsigned long probe_irq_on (void)
259
{
260
        return 0;
261
}
262
 
263
int probe_irq_off (unsigned long irqs)
264
{
265
        return 0;
266
}
267
 
268
void disable_irq(unsigned int irq)
269
{
270
        if (irq && irq < SYS_IRQS)
271
                atmod((void*)IMSK, 1<<(irq-1), 0);
272
}
273
 
274
void enable_irq(unsigned int irq)
275
{
276
        if (irq && irq < SYS_IRQS)
277
                atmod((void*)IMSK, 1<<(irq-1), 1<<(irq-1));
278
}
279
 
280
#ifdef CONFIG_PROF_IRQ
281
#define SAMPLE_BITS     7
282
static inline void
283
update_prof_timers(int vec, unsigned long ticks)
284
{
285
        struct irqstat* irq;
286
        vec = vec >> 4;
287
        irq = irqstat + vec;
288
 
289
        if (!irq->avg)  {
290
                irq->max = ticks;
291
                irq->min = ticks;
292
                irq->avg = ticks;
293
                return;
294
        }
295
 
296
        if (ticks < irq->min)
297
                irq->min = ticks;
298
        if (ticks > irq->max)
299
                irq->max = ticks;
300
        irq->avg -= irq->avg >> SAMPLE_BITS;
301
        irq->avg += ticks >> SAMPLE_BITS;
302
}
303
#endif
304
 
305
/*
306
 * Interrupt service routine. N.B. that XINT0, which is really a system call,
307
 * is never routed to cintr; it ends up in syscall instead.
308
 */
309
extern void do_signal(void);
310
asmlinkage void cintr(unsigned char vec, struct pt_regs* regs)
311
{
312
        extern void timer_interrupt(struct pt_regs* regs);
313
        static int ticks;
314
#ifdef CONFIG_PROF_IRQ
315
        unsigned long clocks;
316
        *TCR1 = CYCLES_PER_HZ * HZ;
317
        *TMR1 = CLOCKDIV1 | CLOCK_ENABLE;
318
#endif
319
        atomic_inc(&intr_count);
320
 
321
        kstat.interrupts[vec >> 4]++;
322
        switch(vec) {
323
                case    NMI_VEC:
324
                        nmi_intr();
325
                        break;
326
 
327
                case    XINT1_VEC:
328
                case    XINT0_VEC:
329
                case    XINT2_VEC:
330
                case    XINT3_VEC:
331
                case    XINT4_VEC:
332
                case    XINT5_VEC:
333
                case    XINT6_VEC:
334
                case    XINT7_VEC:
335
                        xint(vec, regs);
336
                        break;
337
 
338
                case    TMR0_VEC:
339
                        if ((++ticks) >= LED_THRESHOLD) {
340
                                static char nm = 0;
341
                                *LED = ~ (1 << (nm++ % 8));
342
                                ticks = 0;
343
                        }
344
                        timer_interrupt(regs);
345
                        break;
346
 
347
                default:
348
                        bad_intr(vec, regs);
349
                        break;
350
        }
351
        atomic_dec(&intr_count);
352
 
353
        if (!intr_count)
354
                leave_kernel(regs);
355
 
356
#ifdef CONFIG_PROF_IRQ
357
        clocks = CYCLES_PER_HZ*HZ - *TCR1;
358
        update_prof_timers(vec, clocks);
359
#endif
360
        return;
361
}
362
 
363
/*
364
 * Common code to interrupt and syscall paths. When leaving the kernel, and not
365
 * returning to an interrupt context, do a whole bunch of processing.
366
 *
367
 * Note that if we're called from cintr, we're running at high ipl.
368
 *
369
 * Run the bottom half, check if scheduling is needed, and deliver signals to
370
 * the current process, just as in every other architecture.
371
 */
372
void leave_kernel(struct pt_regs* regs)
373
{
374
bh:
375
        if (bh_mask & bh_active) {
376
                atomic_inc(&intr_count);
377
                do_bottom_half();
378
                atomic_dec(&intr_count);
379
        }
380
        sti();
381
 
382
        if (user_mode(regs)) {
383
                if (need_resched) {
384
                        schedule();
385
                        goto bh;
386
                }
387
 
388
 
389
                if (current->signal & ~current->blocked) {
390
                        do_signal();
391
                }
392
        }
393
}
394
 
395
static void nmi_intr(void)
396
{
397
        /* XXX: write me */
398
}
399
 
400
static void bad_intr(unsigned char vec, struct pt_regs* regs)
401
{
402
        /* XXX: write me */
403
        printk("whoah! bad intr: %x\n", vec);
404
}
405
 
406
static void xint(unsigned char vec, struct pt_regs* regs)
407
{
408
        /*
409
         * This basically shouldn't happen
410
         */
411
#ifdef CONFIG_MON960_CONSOLE
412
        if (vec == SERIAL_VEC) {
413
                extern void do_16552_intr(void);
414
                do_16552_intr();
415
                return;
416
        }
417
#endif
418
 
419
#ifdef CONFIG_PCI
420
        if (vec == PCI_VEC && pci_dev) {
421
                pci_isr(0, pci_dev, regs);
422
                return;
423
        }
424
#endif
425
        printk("EEP: xint %x\n", vec);
426
        stack_trace();
427
}
428
 
429
int get_irq_list(char *buf)
430
{
431
        int     len = 0;
432
        int     ii;
433
 
434
        for (ii=0; ii < 16; ii++) {
435
                if (irq_names[ii]) {
436
#ifdef CONFIG_PROF_IRQ
437
                        len += sprintf(buf+len, "%d\t%s\t(%08x, %08x, %08x)\n",
438
                                       kstat.interrupts[ii],
439
                                       (ii==2 && pci_dev)
440
                                       ? pci_name
441
                                       : irq_names[ii],
442
                                       irqstat[ii].min, irqstat[ii].avg,
443
                                       irqstat[ii].max);
444
#else
445
                        len += sprintf(buf+len, "%d\t%s\n",
446
                                       kstat.interrupts[ii],
447
                                       (ii==2 && pci_dev)
448
                                       ? pci_name
449
                                       : irq_names[ii]);
450
#endif
451
                }
452
        }
453
        return len;
454
}
455
 

powered by: WebSVN 2.1.0

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