diff options
Diffstat (limited to 'arch/mips/kernel/irq_cpu.c')
-rw-r--r-- | arch/mips/kernel/irq_cpu.c | 91 |
1 files changed, 77 insertions, 14 deletions
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index 2b936cf1ef70..5db67e31ec1a 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c | |||
@@ -3,6 +3,8 @@ | |||
3 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net | 3 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net |
4 | * | 4 | * |
5 | * Copyright (C) 2001 Ralf Baechle | 5 | * Copyright (C) 2001 Ralf Baechle |
6 | * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. | ||
7 | * Author: Maciej W. Rozycki <macro@mips.com> | ||
6 | * | 8 | * |
7 | * This file define the irq handler for MIPS CPU interrupts. | 9 | * This file define the irq handler for MIPS CPU interrupts. |
8 | * | 10 | * |
@@ -31,19 +33,21 @@ | |||
31 | 33 | ||
32 | #include <asm/irq_cpu.h> | 34 | #include <asm/irq_cpu.h> |
33 | #include <asm/mipsregs.h> | 35 | #include <asm/mipsregs.h> |
36 | #include <asm/mipsmtregs.h> | ||
34 | #include <asm/system.h> | 37 | #include <asm/system.h> |
35 | 38 | ||
36 | static int mips_cpu_irq_base; | 39 | static int mips_cpu_irq_base; |
37 | 40 | ||
38 | static inline void unmask_mips_irq(unsigned int irq) | 41 | static inline void unmask_mips_irq(unsigned int irq) |
39 | { | 42 | { |
40 | clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); | ||
41 | set_c0_status(0x100 << (irq - mips_cpu_irq_base)); | 43 | set_c0_status(0x100 << (irq - mips_cpu_irq_base)); |
44 | irq_enable_hazard(); | ||
42 | } | 45 | } |
43 | 46 | ||
44 | static inline void mask_mips_irq(unsigned int irq) | 47 | static inline void mask_mips_irq(unsigned int irq) |
45 | { | 48 | { |
46 | clear_c0_status(0x100 << (irq - mips_cpu_irq_base)); | 49 | clear_c0_status(0x100 << (irq - mips_cpu_irq_base)); |
50 | irq_disable_hazard(); | ||
47 | } | 51 | } |
48 | 52 | ||
49 | static inline void mips_cpu_irq_enable(unsigned int irq) | 53 | static inline void mips_cpu_irq_enable(unsigned int irq) |
@@ -52,6 +56,7 @@ static inline void mips_cpu_irq_enable(unsigned int irq) | |||
52 | 56 | ||
53 | local_irq_save(flags); | 57 | local_irq_save(flags); |
54 | unmask_mips_irq(irq); | 58 | unmask_mips_irq(irq); |
59 | back_to_back_c0_hazard(); | ||
55 | local_irq_restore(flags); | 60 | local_irq_restore(flags); |
56 | } | 61 | } |
57 | 62 | ||
@@ -61,6 +66,7 @@ static void mips_cpu_irq_disable(unsigned int irq) | |||
61 | 66 | ||
62 | local_irq_save(flags); | 67 | local_irq_save(flags); |
63 | mask_mips_irq(irq); | 68 | mask_mips_irq(irq); |
69 | back_to_back_c0_hazard(); | ||
64 | local_irq_restore(flags); | 70 | local_irq_restore(flags); |
65 | } | 71 | } |
66 | 72 | ||
@@ -71,7 +77,7 @@ static unsigned int mips_cpu_irq_startup(unsigned int irq) | |||
71 | return 0; | 77 | return 0; |
72 | } | 78 | } |
73 | 79 | ||
74 | #define mips_cpu_irq_shutdown mips_cpu_irq_disable | 80 | #define mips_cpu_irq_shutdown mips_cpu_irq_disable |
75 | 81 | ||
76 | /* | 82 | /* |
77 | * While we ack the interrupt interrupts are disabled and thus we don't need | 83 | * While we ack the interrupt interrupts are disabled and thus we don't need |
@@ -79,9 +85,6 @@ static unsigned int mips_cpu_irq_startup(unsigned int irq) | |||
79 | */ | 85 | */ |
80 | static void mips_cpu_irq_ack(unsigned int irq) | 86 | static void mips_cpu_irq_ack(unsigned int irq) |
81 | { | 87 | { |
82 | /* Only necessary for soft interrupts */ | ||
83 | clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); | ||
84 | |||
85 | mask_mips_irq(irq); | 88 | mask_mips_irq(irq); |
86 | } | 89 | } |
87 | 90 | ||
@@ -92,22 +95,82 @@ static void mips_cpu_irq_end(unsigned int irq) | |||
92 | } | 95 | } |
93 | 96 | ||
94 | static hw_irq_controller mips_cpu_irq_controller = { | 97 | static hw_irq_controller mips_cpu_irq_controller = { |
95 | "MIPS", | 98 | .typename = "MIPS", |
96 | mips_cpu_irq_startup, | 99 | .startup = mips_cpu_irq_startup, |
97 | mips_cpu_irq_shutdown, | 100 | .shutdown = mips_cpu_irq_shutdown, |
98 | mips_cpu_irq_enable, | 101 | .enable = mips_cpu_irq_enable, |
99 | mips_cpu_irq_disable, | 102 | .disable = mips_cpu_irq_disable, |
100 | mips_cpu_irq_ack, | 103 | .ack = mips_cpu_irq_ack, |
101 | mips_cpu_irq_end, | 104 | .end = mips_cpu_irq_end, |
102 | NULL /* no affinity stuff for UP */ | ||
103 | }; | 105 | }; |
104 | 106 | ||
107 | /* | ||
108 | * Basically the same as above but taking care of all the MT stuff | ||
109 | */ | ||
110 | |||
111 | #define unmask_mips_mt_irq unmask_mips_irq | ||
112 | #define mask_mips_mt_irq mask_mips_irq | ||
113 | #define mips_mt_cpu_irq_enable mips_cpu_irq_enable | ||
114 | #define mips_mt_cpu_irq_disable mips_cpu_irq_disable | ||
115 | |||
116 | static unsigned int mips_mt_cpu_irq_startup(unsigned int irq) | ||
117 | { | ||
118 | unsigned int vpflags = dvpe(); | ||
119 | |||
120 | clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); | ||
121 | evpe(vpflags); | ||
122 | mips_mt_cpu_irq_enable(irq); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | #define mips_mt_cpu_irq_shutdown mips_mt_cpu_irq_disable | ||
128 | |||
129 | /* | ||
130 | * While we ack the interrupt interrupts are disabled and thus we don't need | ||
131 | * to deal with concurrency issues. Same for mips_cpu_irq_end. | ||
132 | */ | ||
133 | static void mips_mt_cpu_irq_ack(unsigned int irq) | ||
134 | { | ||
135 | unsigned int vpflags = dvpe(); | ||
136 | clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); | ||
137 | evpe(vpflags); | ||
138 | mask_mips_mt_irq(irq); | ||
139 | } | ||
140 | |||
141 | #define mips_mt_cpu_irq_end mips_cpu_irq_end | ||
142 | |||
143 | static hw_irq_controller mips_mt_cpu_irq_controller = { | ||
144 | .typename = "MIPS", | ||
145 | .startup = mips_mt_cpu_irq_startup, | ||
146 | .shutdown = mips_mt_cpu_irq_shutdown, | ||
147 | .enable = mips_mt_cpu_irq_enable, | ||
148 | .disable = mips_mt_cpu_irq_disable, | ||
149 | .ack = mips_mt_cpu_irq_ack, | ||
150 | .end = mips_mt_cpu_irq_end, | ||
151 | }; | ||
105 | 152 | ||
106 | void __init mips_cpu_irq_init(int irq_base) | 153 | void __init mips_cpu_irq_init(int irq_base) |
107 | { | 154 | { |
108 | int i; | 155 | int i; |
109 | 156 | ||
110 | for (i = irq_base; i < irq_base + 8; i++) { | 157 | /* Mask interrupts. */ |
158 | clear_c0_status(ST0_IM); | ||
159 | clear_c0_cause(CAUSEF_IP); | ||
160 | |||
161 | /* | ||
162 | * Only MT is using the software interrupts currently, so we just | ||
163 | * leave them uninitialized for other processors. | ||
164 | */ | ||
165 | if (cpu_has_mipsmt) | ||
166 | for (i = irq_base; i < irq_base + 2; i++) { | ||
167 | irq_desc[i].status = IRQ_DISABLED; | ||
168 | irq_desc[i].action = NULL; | ||
169 | irq_desc[i].depth = 1; | ||
170 | irq_desc[i].handler = &mips_mt_cpu_irq_controller; | ||
171 | } | ||
172 | |||
173 | for (i = irq_base + 2; i < irq_base + 8; i++) { | ||
111 | irq_desc[i].status = IRQ_DISABLED; | 174 | irq_desc[i].status = IRQ_DISABLED; |
112 | irq_desc[i].action = NULL; | 175 | irq_desc[i].action = NULL; |
113 | irq_desc[i].depth = 1; | 176 | irq_desc[i].depth = 1; |