]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | } |