diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/v850/kernel/v850e_intc.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/v850/kernel/v850e_intc.c')
-rw-r--r-- | arch/v850/kernel/v850e_intc.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/arch/v850/kernel/v850e_intc.c b/arch/v850/kernel/v850e_intc.c new file mode 100644 index 000000000000..8d39a52ee6d1 --- /dev/null +++ b/arch/v850/kernel/v850e_intc.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * arch/v850/kernel/v850e_intc.c -- V850E interrupt controller (INTC) | ||
3 | * | ||
4 | * Copyright (C) 2001,02,03 NEC Electronics Corporation | ||
5 | * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General | ||
8 | * Public License. See the file COPYING in the main directory of this | ||
9 | * archive for more details. | ||
10 | * | ||
11 | * Written by Miles Bader <miles@gnu.org> | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/irq.h> | ||
17 | |||
18 | #include <asm/v850e_intc.h> | ||
19 | |||
20 | static void irq_nop (unsigned irq) { } | ||
21 | |||
22 | static unsigned v850e_intc_irq_startup (unsigned irq) | ||
23 | { | ||
24 | v850e_intc_clear_pending_irq (irq); | ||
25 | v850e_intc_enable_irq (irq); | ||
26 | return 0; | ||
27 | } | ||
28 | |||
29 | static void v850e_intc_end_irq (unsigned irq) | ||
30 | { | ||
31 | unsigned long psw, temp; | ||
32 | |||
33 | /* Clear the highest-level bit in the In-service priority register | ||
34 | (ISPR), to allow this interrupt (or another of the same or | ||
35 | lesser priority) to happen again. | ||
36 | |||
37 | The `reti' instruction normally does this automatically when the | ||
38 | PSW bits EP and NP are zero, but we can't always rely on reti | ||
39 | being used consistently to return after an interrupt (another | ||
40 | process can be scheduled, for instance, which can delay the | ||
41 | associated reti for a long time, or this process may be being | ||
42 | single-stepped, which uses the `dbret' instruction to return | ||
43 | from the kernel). | ||
44 | |||
45 | We also set the PSW EP bit, which prevents reti from also | ||
46 | trying to modify the ISPR itself. */ | ||
47 | |||
48 | /* Get PSW and disable interrupts. */ | ||
49 | asm volatile ("stsr psw, %0; di" : "=r" (psw)); | ||
50 | /* We don't want to do anything for NMIs (they don't use the ISPR). */ | ||
51 | if (! (psw & 0xC0)) { | ||
52 | /* Transition to `trap' state, so that an eventual real | ||
53 | reti instruction won't modify the ISPR. */ | ||
54 | psw |= 0x40; | ||
55 | /* Fake an interrupt return, which automatically clears the | ||
56 | appropriate bit in the ISPR. */ | ||
57 | asm volatile ("mov hilo(1f), %0;" | ||
58 | "ldsr %0, eipc; ldsr %1, eipsw;" | ||
59 | "reti;" | ||
60 | "1:" | ||
61 | : "=&r" (temp) : "r" (psw)); | ||
62 | } | ||
63 | } | ||
64 | |||
65 | /* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array | ||
66 | INITS (which is terminated by an entry with the name field == 0). */ | ||
67 | void __init v850e_intc_init_irq_types (struct v850e_intc_irq_init *inits, | ||
68 | struct hw_interrupt_type *hw_irq_types) | ||
69 | { | ||
70 | struct v850e_intc_irq_init *init; | ||
71 | for (init = inits; init->name; init++) { | ||
72 | unsigned i; | ||
73 | struct hw_interrupt_type *hwit = hw_irq_types++; | ||
74 | |||
75 | hwit->typename = init->name; | ||
76 | |||
77 | hwit->startup = v850e_intc_irq_startup; | ||
78 | hwit->shutdown = v850e_intc_disable_irq; | ||
79 | hwit->enable = v850e_intc_enable_irq; | ||
80 | hwit->disable = v850e_intc_disable_irq; | ||
81 | hwit->ack = irq_nop; | ||
82 | hwit->end = v850e_intc_end_irq; | ||
83 | |||
84 | /* Initialize kernel IRQ infrastructure for this interrupt. */ | ||
85 | init_irq_handlers(init->base, init->num, init->interval, hwit); | ||
86 | |||
87 | /* Set the interrupt priorities. */ | ||
88 | for (i = 0; i < init->num; i++) { | ||
89 | unsigned irq = init->base + i * init->interval; | ||
90 | |||
91 | /* If the interrupt is currently enabled (all | ||
92 | interrupts are initially disabled), then | ||
93 | assume whoever enabled it has set things up | ||
94 | properly, and avoid messing with it. */ | ||
95 | if (! v850e_intc_irq_enabled (irq)) | ||
96 | /* This write also (1) disables the | ||
97 | interrupt, and (2) clears any pending | ||
98 | interrupts. */ | ||
99 | V850E_INTC_IC (irq) | ||
100 | = (V850E_INTC_IC_PR (init->priority) | ||
101 | | V850E_INTC_IC_MK); | ||
102 | } | ||
103 | } | ||
104 | } | ||