diff options
Diffstat (limited to 'arch/sparc/kernel/sun4c_irq.c')
-rw-r--r-- | arch/sparc/kernel/sun4c_irq.c | 156 |
1 files changed, 59 insertions, 97 deletions
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c index 340fc395fe2d..5dc8a5769489 100644 --- a/arch/sparc/kernel/sun4c_irq.c +++ b/arch/sparc/kernel/sun4c_irq.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/of.h> | ||
22 | #include <linux/of_device.h> | ||
21 | #include "irq.h" | 23 | #include "irq.h" |
22 | 24 | ||
23 | #include <asm/ptrace.h> | 25 | #include <asm/ptrace.h> |
@@ -31,15 +33,8 @@ | |||
31 | #include <asm/traps.h> | 33 | #include <asm/traps.h> |
32 | #include <asm/irq.h> | 34 | #include <asm/irq.h> |
33 | #include <asm/io.h> | 35 | #include <asm/io.h> |
34 | #include <asm/sun4paddr.h> | ||
35 | #include <asm/idprom.h> | 36 | #include <asm/idprom.h> |
36 | #include <asm/machines.h> | 37 | #include <asm/machines.h> |
37 | #include <asm/sbus.h> | ||
38 | |||
39 | #if 0 | ||
40 | static struct resource sun4c_timer_eb = { "sun4c_timer" }; | ||
41 | static struct resource sun4c_intr_eb = { "sun4c_intr" }; | ||
42 | #endif | ||
43 | 38 | ||
44 | /* | 39 | /* |
45 | * Bit field defines for the interrupt registers on various | 40 | * Bit field defines for the interrupt registers on various |
@@ -64,19 +59,7 @@ static struct resource sun4c_intr_eb = { "sun4c_intr" }; | |||
64 | * | 59 | * |
65 | * so don't go making it static, like I tried. sigh. | 60 | * so don't go making it static, like I tried. sigh. |
66 | */ | 61 | */ |
67 | unsigned char *interrupt_enable = NULL; | 62 | unsigned char __iomem *interrupt_enable = NULL; |
68 | |||
69 | static int sun4c_pil_map[] = { 0, 1, 2, 3, 5, 7, 8, 9 }; | ||
70 | |||
71 | static unsigned int sun4c_sbint_to_irq(struct sbus_dev *sdev, | ||
72 | unsigned int sbint) | ||
73 | { | ||
74 | if (sbint >= sizeof(sun4c_pil_map)) { | ||
75 | printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint); | ||
76 | BUG(); | ||
77 | } | ||
78 | return sun4c_pil_map[sbint]; | ||
79 | } | ||
80 | 63 | ||
81 | static void sun4c_disable_irq(unsigned int irq_nr) | 64 | static void sun4c_disable_irq(unsigned int irq_nr) |
82 | { | 65 | { |
@@ -85,7 +68,7 @@ static void sun4c_disable_irq(unsigned int irq_nr) | |||
85 | 68 | ||
86 | local_irq_save(flags); | 69 | local_irq_save(flags); |
87 | irq_nr &= (NR_IRQS - 1); | 70 | irq_nr &= (NR_IRQS - 1); |
88 | current_mask = *interrupt_enable; | 71 | current_mask = sbus_readb(interrupt_enable); |
89 | switch(irq_nr) { | 72 | switch(irq_nr) { |
90 | case 1: | 73 | case 1: |
91 | new_mask = ((current_mask) & (~(SUN4C_INT_E1))); | 74 | new_mask = ((current_mask) & (~(SUN4C_INT_E1))); |
@@ -103,7 +86,7 @@ static void sun4c_disable_irq(unsigned int irq_nr) | |||
103 | local_irq_restore(flags); | 86 | local_irq_restore(flags); |
104 | return; | 87 | return; |
105 | } | 88 | } |
106 | *interrupt_enable = new_mask; | 89 | sbus_writeb(new_mask, interrupt_enable); |
107 | local_irq_restore(flags); | 90 | local_irq_restore(flags); |
108 | } | 91 | } |
109 | 92 | ||
@@ -114,7 +97,7 @@ static void sun4c_enable_irq(unsigned int irq_nr) | |||
114 | 97 | ||
115 | local_irq_save(flags); | 98 | local_irq_save(flags); |
116 | irq_nr &= (NR_IRQS - 1); | 99 | irq_nr &= (NR_IRQS - 1); |
117 | current_mask = *interrupt_enable; | 100 | current_mask = sbus_readb(interrupt_enable); |
118 | switch(irq_nr) { | 101 | switch(irq_nr) { |
119 | case 1: | 102 | case 1: |
120 | new_mask = ((current_mask) | SUN4C_INT_E1); | 103 | new_mask = ((current_mask) | SUN4C_INT_E1); |
@@ -132,37 +115,22 @@ static void sun4c_enable_irq(unsigned int irq_nr) | |||
132 | local_irq_restore(flags); | 115 | local_irq_restore(flags); |
133 | return; | 116 | return; |
134 | } | 117 | } |
135 | *interrupt_enable = new_mask; | 118 | sbus_writeb(new_mask, interrupt_enable); |
136 | local_irq_restore(flags); | 119 | local_irq_restore(flags); |
137 | } | 120 | } |
138 | 121 | ||
139 | #define TIMER_IRQ 10 /* Also at level 14, but we ignore that one. */ | 122 | struct sun4c_timer_info { |
140 | #define PROFILE_IRQ 14 /* Level14 ticker.. used by OBP for polling */ | 123 | u32 l10_count; |
141 | 124 | u32 l10_limit; | |
142 | volatile struct sun4c_timer_info *sun4c_timers; | 125 | u32 l14_count; |
126 | u32 l14_limit; | ||
127 | }; | ||
143 | 128 | ||
144 | #ifdef CONFIG_SUN4 | 129 | static struct sun4c_timer_info __iomem *sun4c_timers; |
145 | /* This is an ugly hack to work around the | ||
146 | current timer code, and make it work with | ||
147 | the sun4/260 intersil | ||
148 | */ | ||
149 | volatile struct sun4c_timer_info sun4_timer; | ||
150 | #endif | ||
151 | 130 | ||
152 | static void sun4c_clear_clock_irq(void) | 131 | static void sun4c_clear_clock_irq(void) |
153 | { | 132 | { |
154 | volatile unsigned int clear_intr; | 133 | sbus_readl(&sun4c_timers->l10_limit); |
155 | #ifdef CONFIG_SUN4 | ||
156 | if (idprom->id_machtype == (SM_SUN4 | SM_4_260)) | ||
157 | clear_intr = sun4_timer.timer_limit10; | ||
158 | else | ||
159 | #endif | ||
160 | clear_intr = sun4c_timers->timer_limit10; | ||
161 | } | ||
162 | |||
163 | static void sun4c_clear_profile_irq(int cpu) | ||
164 | { | ||
165 | /* Errm.. not sure how to do this.. */ | ||
166 | } | 134 | } |
167 | 135 | ||
168 | static void sun4c_load_profile_irq(int cpu, unsigned int limit) | 136 | static void sun4c_load_profile_irq(int cpu, unsigned int limit) |
@@ -172,41 +140,48 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit) | |||
172 | 140 | ||
173 | static void __init sun4c_init_timers(irq_handler_t counter_fn) | 141 | static void __init sun4c_init_timers(irq_handler_t counter_fn) |
174 | { | 142 | { |
175 | int irq; | 143 | const struct linux_prom_irqs *irq; |
144 | struct device_node *dp; | ||
145 | const u32 *addr; | ||
146 | int err; | ||
147 | |||
148 | dp = of_find_node_by_name(NULL, "counter-timer"); | ||
149 | if (!dp) { | ||
150 | prom_printf("sun4c_init_timers: Unable to find counter-timer\n"); | ||
151 | prom_halt(); | ||
152 | } | ||
176 | 153 | ||
177 | /* Map the Timer chip, this is implemented in hardware inside | 154 | addr = of_get_property(dp, "address", NULL); |
178 | * the cache chip on the sun4c. | 155 | if (!addr) { |
179 | */ | 156 | prom_printf("sun4c_init_timers: No address property\n"); |
180 | #ifdef CONFIG_SUN4 | 157 | prom_halt(); |
181 | if (idprom->id_machtype == (SM_SUN4 | SM_4_260)) | 158 | } |
182 | sun4c_timers = &sun4_timer; | 159 | |
183 | else | 160 | sun4c_timers = (void __iomem *) (unsigned long) addr[0]; |
184 | #endif | 161 | |
185 | sun4c_timers = ioremap(SUN_TIMER_PHYSADDR, | 162 | irq = of_get_property(dp, "intr", NULL); |
186 | sizeof(struct sun4c_timer_info)); | 163 | if (!irq) { |
164 | prom_printf("sun4c_init_timers: No intr property\n"); | ||
165 | prom_halt(); | ||
166 | } | ||
187 | 167 | ||
188 | /* Have the level 10 timer tick at 100HZ. We don't touch the | 168 | /* Have the level 10 timer tick at 100HZ. We don't touch the |
189 | * level 14 timer limit since we are letting the prom handle | 169 | * level 14 timer limit since we are letting the prom handle |
190 | * them until we have a real console driver so L1-A works. | 170 | * them until we have a real console driver so L1-A works. |
191 | */ | 171 | */ |
192 | sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10); | 172 | sbus_writel((((1000000/HZ) + 1) << 10), &sun4c_timers->l10_limit); |
193 | master_l10_counter = &sun4c_timers->cur_count10; | ||
194 | master_l10_limit = &sun4c_timers->timer_limit10; | ||
195 | 173 | ||
196 | irq = request_irq(TIMER_IRQ, | 174 | master_l10_counter = &sun4c_timers->l10_count; |
197 | counter_fn, | 175 | |
176 | err = request_irq(irq[0].pri, counter_fn, | ||
198 | (IRQF_DISABLED | SA_STATIC_ALLOC), | 177 | (IRQF_DISABLED | SA_STATIC_ALLOC), |
199 | "timer", NULL); | 178 | "timer", NULL); |
200 | if (irq) { | 179 | if (err) { |
201 | prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); | 180 | prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err); |
202 | prom_halt(); | 181 | prom_halt(); |
203 | } | 182 | } |
204 | 183 | ||
205 | #if 0 | 184 | sun4c_disable_irq(irq[1].pri); |
206 | /* This does not work on 4/330 */ | ||
207 | sun4c_enable_irq(10); | ||
208 | #endif | ||
209 | claim_ticker14(NULL, PROFILE_IRQ, 0); | ||
210 | } | 185 | } |
211 | 186 | ||
212 | #ifdef CONFIG_SMP | 187 | #ifdef CONFIG_SMP |
@@ -215,41 +190,28 @@ static void sun4c_nop(void) {} | |||
215 | 190 | ||
216 | void __init sun4c_init_IRQ(void) | 191 | void __init sun4c_init_IRQ(void) |
217 | { | 192 | { |
218 | struct linux_prom_registers int_regs[2]; | 193 | struct device_node *dp; |
219 | int ie_node; | 194 | const u32 *addr; |
220 | 195 | ||
221 | if (ARCH_SUN4) { | 196 | dp = of_find_node_by_name(NULL, "interrupt-enable"); |
222 | interrupt_enable = (char *) | 197 | if (!dp) { |
223 | ioremap(sun4_ie_physaddr, PAGE_SIZE); | 198 | prom_printf("sun4c_init_IRQ: Unable to find interrupt-enable\n"); |
224 | } else { | 199 | prom_halt(); |
225 | struct resource phyres; | 200 | } |
226 | |||
227 | ie_node = prom_searchsiblings (prom_getchild(prom_root_node), | ||
228 | "interrupt-enable"); | ||
229 | if(ie_node == 0) | ||
230 | panic("Cannot find /interrupt-enable node"); | ||
231 | 201 | ||
232 | /* Depending on the "address" property is bad news... */ | 202 | addr = of_get_property(dp, "address", NULL); |
233 | interrupt_enable = NULL; | 203 | if (!addr) { |
234 | if (prom_getproperty(ie_node, "reg", (char *) int_regs, | 204 | prom_printf("sun4c_init_IRQ: No address property\n"); |
235 | sizeof(int_regs)) != -1) { | 205 | prom_halt(); |
236 | memset(&phyres, 0, sizeof(struct resource)); | ||
237 | phyres.flags = int_regs[0].which_io; | ||
238 | phyres.start = int_regs[0].phys_addr; | ||
239 | interrupt_enable = (char *) sbus_ioremap(&phyres, 0, | ||
240 | int_regs[0].reg_size, "sun4c_intr"); | ||
241 | } | ||
242 | } | 206 | } |
243 | if (!interrupt_enable) | ||
244 | panic("Cannot map interrupt_enable"); | ||
245 | 207 | ||
246 | BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM); | 208 | interrupt_enable = (void __iomem *) (unsigned long) addr[0]; |
209 | |||
247 | BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); | 210 | BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); |
248 | BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); | 211 | BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); |
249 | BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); | 212 | BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); |
250 | BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); | 213 | BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); |
251 | BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); | 214 | BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); |
252 | BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP); | ||
253 | BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); | 215 | BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); |
254 | sparc_init_timers = sun4c_init_timers; | 216 | sparc_init_timers = sun4c_init_timers; |
255 | #ifdef CONFIG_SMP | 217 | #ifdef CONFIG_SMP |
@@ -257,6 +219,6 @@ void __init sun4c_init_IRQ(void) | |||
257 | BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); | 219 | BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); |
258 | BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP); | 220 | BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP); |
259 | #endif | 221 | #endif |
260 | *interrupt_enable = (SUN4C_INT_ENABLE); | 222 | sbus_writeb(SUN4C_INT_ENABLE, interrupt_enable); |
261 | /* Cannot enable interrupts until OBP ticker is disabled. */ | 223 | /* Cannot enable interrupts until OBP ticker is disabled. */ |
262 | } | 224 | } |