diff options
-rw-r--r-- | arch/sparc/Kconfig | 6 | ||||
-rw-r--r-- | arch/sparc/include/asm/floppy_32.h | 40 | ||||
-rw-r--r-- | arch/sparc/include/asm/irq_32.h | 6 | ||||
-rw-r--r-- | arch/sparc/include/asm/system_32.h | 5 | ||||
-rw-r--r-- | arch/sparc/kernel/Makefile | 4 | ||||
-rw-r--r-- | arch/sparc/kernel/irq.h | 45 | ||||
-rw-r--r-- | arch/sparc/kernel/irq_32.c | 494 | ||||
-rw-r--r-- | arch/sparc/kernel/kernel.h | 1 | ||||
-rw-r--r-- | arch/sparc/kernel/leon_kernel.c | 70 | ||||
-rw-r--r-- | arch/sparc/kernel/pcic.c | 83 | ||||
-rw-r--r-- | arch/sparc/kernel/sun4c_irq.c | 150 | ||||
-rw-r--r-- | arch/sparc/kernel/sun4d_irq.c | 472 | ||||
-rw-r--r-- | arch/sparc/kernel/sun4m_irq.c | 179 | ||||
-rw-r--r-- | arch/sparc/kernel/sun4m_smp.c | 16 |
14 files changed, 636 insertions, 935 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index e560d102215a..a56630d4f14b 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig | |||
@@ -25,6 +25,10 @@ config SPARC | |||
25 | select HAVE_DMA_ATTRS | 25 | select HAVE_DMA_ATTRS |
26 | select HAVE_DMA_API_DEBUG | 26 | select HAVE_DMA_API_DEBUG |
27 | select HAVE_ARCH_JUMP_LABEL | 27 | select HAVE_ARCH_JUMP_LABEL |
28 | select HAVE_GENERIC_HARDIRQS | ||
29 | select GENERIC_HARDIRQS_NO_DEPRECATED | ||
30 | select GENERIC_IRQ_SHOW | ||
31 | |||
28 | 32 | ||
29 | config SPARC32 | 33 | config SPARC32 |
30 | def_bool !64BIT | 34 | def_bool !64BIT |
@@ -50,8 +54,6 @@ config SPARC64 | |||
50 | select RTC_DRV_STARFIRE | 54 | select RTC_DRV_STARFIRE |
51 | select HAVE_PERF_EVENTS | 55 | select HAVE_PERF_EVENTS |
52 | select PERF_USE_VMALLOC | 56 | select PERF_USE_VMALLOC |
53 | select HAVE_GENERIC_HARDIRQS | ||
54 | select GENERIC_IRQ_SHOW | ||
55 | select IRQ_PREFLOW_FASTEOI | 57 | select IRQ_PREFLOW_FASTEOI |
56 | 58 | ||
57 | config ARCH_DEFCONFIG | 59 | config ARCH_DEFCONFIG |
diff --git a/arch/sparc/include/asm/floppy_32.h b/arch/sparc/include/asm/floppy_32.h index 86666f70322e..482c79e2a416 100644 --- a/arch/sparc/include/asm/floppy_32.h +++ b/arch/sparc/include/asm/floppy_32.h | |||
@@ -281,28 +281,27 @@ static inline void sun_fd_enable_dma(void) | |||
281 | pdma_areasize = pdma_size; | 281 | pdma_areasize = pdma_size; |
282 | } | 282 | } |
283 | 283 | ||
284 | /* Our low-level entry point in arch/sparc/kernel/entry.S */ | 284 | extern int sparc_floppy_request_irq(unsigned int irq, |
285 | extern int sparc_floppy_request_irq(int irq, unsigned long flags, | 285 | irq_handler_t irq_handler); |
286 | irq_handler_t irq_handler); | ||
287 | 286 | ||
288 | static int sun_fd_request_irq(void) | 287 | static int sun_fd_request_irq(void) |
289 | { | 288 | { |
290 | static int once = 0; | 289 | static int once = 0; |
291 | int error; | ||
292 | 290 | ||
293 | if(!once) { | 291 | if (!once) { |
294 | once = 1; | 292 | once = 1; |
295 | error = sparc_floppy_request_irq(FLOPPY_IRQ, | 293 | return sparc_floppy_request_irq(FLOPPY_IRQ, floppy_interrupt); |
296 | IRQF_DISABLED, | 294 | } else { |
297 | floppy_interrupt); | 295 | return 0; |
298 | return ((error == 0) ? 0 : -1); | 296 | } |
299 | } else return 0; | ||
300 | } | 297 | } |
301 | 298 | ||
302 | static struct linux_prom_registers fd_regs[2]; | 299 | static struct linux_prom_registers fd_regs[2]; |
303 | 300 | ||
304 | static int sun_floppy_init(void) | 301 | static int sun_floppy_init(void) |
305 | { | 302 | { |
303 | struct platform_device *op; | ||
304 | struct device_node *dp; | ||
306 | char state[128]; | 305 | char state[128]; |
307 | phandle tnode, fd_node; | 306 | phandle tnode, fd_node; |
308 | int num_regs; | 307 | int num_regs; |
@@ -310,7 +309,6 @@ static int sun_floppy_init(void) | |||
310 | 309 | ||
311 | use_virtual_dma = 1; | 310 | use_virtual_dma = 1; |
312 | 311 | ||
313 | FLOPPY_IRQ = 11; | ||
314 | /* Forget it if we aren't on a machine that could possibly | 312 | /* Forget it if we aren't on a machine that could possibly |
315 | * ever have a floppy drive. | 313 | * ever have a floppy drive. |
316 | */ | 314 | */ |
@@ -349,6 +347,26 @@ static int sun_floppy_init(void) | |||
349 | sun_fdc = (struct sun_flpy_controller *) | 347 | sun_fdc = (struct sun_flpy_controller *) |
350 | of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy"); | 348 | of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy"); |
351 | 349 | ||
350 | /* Look up irq in platform_device. | ||
351 | * We try "SUNW,fdtwo" and "fd" | ||
352 | */ | ||
353 | for_each_node_by_name(dp, "SUNW,fdtwo") { | ||
354 | op = of_find_device_by_node(dp); | ||
355 | if (op) | ||
356 | break; | ||
357 | } | ||
358 | if (!op) { | ||
359 | for_each_node_by_name(dp, "fd") { | ||
360 | op = of_find_device_by_node(dp); | ||
361 | if (op) | ||
362 | break; | ||
363 | } | ||
364 | } | ||
365 | if (!op) | ||
366 | goto no_sun_fdc; | ||
367 | |||
368 | FLOPPY_IRQ = op->archdata.irqs[0]; | ||
369 | |||
352 | /* Last minute sanity check... */ | 370 | /* Last minute sanity check... */ |
353 | if(sun_fdc->status_82072 == 0xff) { | 371 | if(sun_fdc->status_82072 == 0xff) { |
354 | sun_fdc = NULL; | 372 | sun_fdc = NULL; |
diff --git a/arch/sparc/include/asm/irq_32.h b/arch/sparc/include/asm/irq_32.h index eced3e3ebd30..2ae3acaeb1b3 100644 --- a/arch/sparc/include/asm/irq_32.h +++ b/arch/sparc/include/asm/irq_32.h | |||
@@ -6,7 +6,11 @@ | |||
6 | #ifndef _SPARC_IRQ_H | 6 | #ifndef _SPARC_IRQ_H |
7 | #define _SPARC_IRQ_H | 7 | #define _SPARC_IRQ_H |
8 | 8 | ||
9 | #define NR_IRQS 16 | 9 | /* Allocated number of logical irq numbers. |
10 | * sun4d boxes (ss2000e) should be OK with ~32. | ||
11 | * Be on the safe side and make room for 64 | ||
12 | */ | ||
13 | #define NR_IRQS 64 | ||
10 | 14 | ||
11 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
12 | 16 | ||
diff --git a/arch/sparc/include/asm/system_32.h b/arch/sparc/include/asm/system_32.h index 890036b3689a..47a7e862474e 100644 --- a/arch/sparc/include/asm/system_32.h +++ b/arch/sparc/include/asm/system_32.h | |||
@@ -15,11 +15,6 @@ | |||
15 | 15 | ||
16 | #include <linux/irqflags.h> | 16 | #include <linux/irqflags.h> |
17 | 17 | ||
18 | static inline unsigned int probe_irq_mask(unsigned long val) | ||
19 | { | ||
20 | return 0; | ||
21 | } | ||
22 | |||
23 | /* | 18 | /* |
24 | * Sparc (general) CPU types | 19 | * Sparc (general) CPU types |
25 | */ | 20 | */ |
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 99aa4db6e9c2..9cff2709a96d 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile | |||
@@ -71,10 +71,6 @@ obj-$(CONFIG_SPARC64) += pcr.o | |||
71 | obj-$(CONFIG_SPARC64) += nmi.o | 71 | obj-$(CONFIG_SPARC64) += nmi.o |
72 | obj-$(CONFIG_SPARC64_SMP) += cpumap.o | 72 | obj-$(CONFIG_SPARC64_SMP) += cpumap.o |
73 | 73 | ||
74 | # sparc32 do not use GENERIC_HARDIRQS but uses the generic devres implementation | ||
75 | obj-$(CONFIG_SPARC32) += devres.o | ||
76 | devres-y := ../../../kernel/irq/devres.o | ||
77 | |||
78 | obj-y += dma.o | 74 | obj-y += dma.o |
79 | 75 | ||
80 | obj-$(CONFIG_SPARC32_PCI) += pcic.o | 76 | obj-$(CONFIG_SPARC32_PCI) += pcic.o |
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h index 008453b798ec..a189c273f638 100644 --- a/arch/sparc/kernel/irq.h +++ b/arch/sparc/kernel/irq.h | |||
@@ -2,6 +2,23 @@ | |||
2 | 2 | ||
3 | #include <asm/btfixup.h> | 3 | #include <asm/btfixup.h> |
4 | 4 | ||
5 | struct irq_bucket { | ||
6 | struct irq_bucket *next; | ||
7 | unsigned int real_irq; | ||
8 | unsigned int irq; | ||
9 | unsigned int pil; | ||
10 | }; | ||
11 | |||
12 | #define SUN4D_MAX_BOARD 10 | ||
13 | #define SUN4D_MAX_IRQ ((SUN4D_MAX_BOARD + 2) << 5) | ||
14 | |||
15 | /* Map between the irq identifier used in hw to the | ||
16 | * irq_bucket. The map is sufficient large to hold | ||
17 | * the sun4d hw identifiers. | ||
18 | */ | ||
19 | extern struct irq_bucket *irq_map[SUN4D_MAX_IRQ]; | ||
20 | |||
21 | |||
5 | /* sun4m specific type definitions */ | 22 | /* sun4m specific type definitions */ |
6 | 23 | ||
7 | /* This maps direct to CPU specific interrupt registers */ | 24 | /* This maps direct to CPU specific interrupt registers */ |
@@ -35,6 +52,10 @@ struct sparc_irq_config { | |||
35 | }; | 52 | }; |
36 | extern struct sparc_irq_config sparc_irq_config; | 53 | extern struct sparc_irq_config sparc_irq_config; |
37 | 54 | ||
55 | unsigned int irq_alloc(unsigned int real_irq, unsigned int pil); | ||
56 | void irq_link(unsigned int irq); | ||
57 | void irq_unlink(unsigned int irq); | ||
58 | void handler_irq(unsigned int pil, struct pt_regs *regs); | ||
38 | 59 | ||
39 | /* Dave Redman (djhr@tadpole.co.uk) | 60 | /* Dave Redman (djhr@tadpole.co.uk) |
40 | * changed these to function pointers.. it saves cycles and will allow | 61 | * changed these to function pointers.. it saves cycles and will allow |
@@ -44,33 +65,9 @@ extern struct sparc_irq_config sparc_irq_config; | |||
44 | * Changed these to btfixup entities... It saves cycles :) | 65 | * Changed these to btfixup entities... It saves cycles :) |
45 | */ | 66 | */ |
46 | 67 | ||
47 | BTFIXUPDEF_CALL(void, disable_irq, unsigned int) | ||
48 | BTFIXUPDEF_CALL(void, enable_irq, unsigned int) | ||
49 | BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int) | ||
50 | BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int) | ||
51 | BTFIXUPDEF_CALL(void, clear_clock_irq, void) | 68 | BTFIXUPDEF_CALL(void, clear_clock_irq, void) |
52 | BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int) | 69 | BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int) |
53 | 70 | ||
54 | static inline void __disable_irq(unsigned int irq) | ||
55 | { | ||
56 | BTFIXUP_CALL(disable_irq)(irq); | ||
57 | } | ||
58 | |||
59 | static inline void __enable_irq(unsigned int irq) | ||
60 | { | ||
61 | BTFIXUP_CALL(enable_irq)(irq); | ||
62 | } | ||
63 | |||
64 | static inline void disable_pil_irq(unsigned int irq) | ||
65 | { | ||
66 | BTFIXUP_CALL(disable_pil_irq)(irq); | ||
67 | } | ||
68 | |||
69 | static inline void enable_pil_irq(unsigned int irq) | ||
70 | { | ||
71 | BTFIXUP_CALL(enable_pil_irq)(irq); | ||
72 | } | ||
73 | |||
74 | static inline void clear_clock_irq(void) | 71 | static inline void clear_clock_irq(void) |
75 | { | 72 | { |
76 | BTFIXUP_CALL(clear_clock_irq)(); | 73 | BTFIXUP_CALL(clear_clock_irq)(); |
diff --git a/arch/sparc/kernel/irq_32.c b/arch/sparc/kernel/irq_32.c index b2dbb4ba8608..197e1ba85484 100644 --- a/arch/sparc/kernel/irq_32.c +++ b/arch/sparc/kernel/irq_32.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/seq_file.h> | 15 | #include <linux/seq_file.h> |
16 | 16 | ||
17 | #include <asm/cacheflush.h> | 17 | #include <asm/cacheflush.h> |
18 | #include <asm/cpudata.h> | ||
18 | #include <asm/pcic.h> | 19 | #include <asm/pcic.h> |
19 | #include <asm/leon.h> | 20 | #include <asm/leon.h> |
20 | 21 | ||
@@ -101,284 +102,163 @@ EXPORT_SYMBOL(arch_local_irq_restore); | |||
101 | * directed CPU interrupts using the existing enable/disable irq code | 102 | * directed CPU interrupts using the existing enable/disable irq code |
102 | * with tweaks. | 103 | * with tweaks. |
103 | * | 104 | * |
105 | * Sun4d complicates things even further. IRQ numbers are arbitrary | ||
106 | * 32-bit values in that case. Since this is similar to sparc64, | ||
107 | * we adopt a virtual IRQ numbering scheme as is done there. | ||
108 | * Virutal interrupt numbers are allocated by build_irq(). So NR_IRQS | ||
109 | * just becomes a limit of how many interrupt sources we can handle in | ||
110 | * a single system. Even fully loaded SS2000 machines top off at | ||
111 | * about 32 interrupt sources or so, therefore a NR_IRQS value of 64 | ||
112 | * is more than enough. | ||
113 | * | ||
114 | * We keep a map of per-PIL enable interrupts. These get wired | ||
115 | * up via the irq_chip->startup() method which gets invoked by | ||
116 | * the generic IRQ layer during request_irq(). | ||
104 | */ | 117 | */ |
105 | 118 | ||
106 | 119 | ||
120 | /* Table of allocated irqs. Unused entries has irq == 0 */ | ||
121 | static struct irq_bucket irq_table[NR_IRQS]; | ||
122 | /* Protect access to irq_table */ | ||
123 | static DEFINE_SPINLOCK(irq_table_lock); | ||
107 | 124 | ||
108 | /* | 125 | /* Map between the irq identifier used in hw to the irq_bucket. */ |
109 | * Dave Redman (djhr@tadpole.co.uk) | 126 | struct irq_bucket *irq_map[SUN4D_MAX_IRQ]; |
110 | * | 127 | /* Protect access to irq_map */ |
111 | * There used to be extern calls and hard coded values here.. very sucky! | 128 | static DEFINE_SPINLOCK(irq_map_lock); |
112 | * instead, because some of the devices attach very early, I do something | ||
113 | * equally sucky but at least we'll never try to free statically allocated | ||
114 | * space or call kmalloc before kmalloc_init :(. | ||
115 | * | ||
116 | * In fact it's the timer10 that attaches first.. then timer14 | ||
117 | * then kmalloc_init is called.. then the tty interrupts attach. | ||
118 | * hmmm.... | ||
119 | * | ||
120 | */ | ||
121 | #define MAX_STATIC_ALLOC 4 | ||
122 | struct irqaction static_irqaction[MAX_STATIC_ALLOC]; | ||
123 | int static_irq_count; | ||
124 | |||
125 | static struct { | ||
126 | struct irqaction *action; | ||
127 | int flags; | ||
128 | } sparc_irq[NR_IRQS]; | ||
129 | #define SPARC_IRQ_INPROGRESS 1 | ||
130 | |||
131 | /* Used to protect the IRQ action lists */ | ||
132 | DEFINE_SPINLOCK(irq_action_lock); | ||
133 | 129 | ||
134 | int show_interrupts(struct seq_file *p, void *v) | 130 | /* Allocate a new irq from the irq_table */ |
131 | unsigned int irq_alloc(unsigned int real_irq, unsigned int pil) | ||
135 | { | 132 | { |
136 | int i = *(loff_t *)v; | ||
137 | struct irqaction *action; | ||
138 | unsigned long flags; | 133 | unsigned long flags; |
139 | #ifdef CONFIG_SMP | 134 | unsigned int i; |
140 | int j; | 135 | |
141 | #endif | 136 | spin_lock_irqsave(&irq_table_lock, flags); |
137 | for (i = 1; i < NR_IRQS; i++) { | ||
138 | if (irq_table[i].real_irq == real_irq && irq_table[i].pil == pil) | ||
139 | goto found; | ||
140 | } | ||
142 | 141 | ||
143 | if (sparc_cpu_model == sun4d) | 142 | for (i = 1; i < NR_IRQS; i++) { |
144 | return show_sun4d_interrupts(p, v); | 143 | if (!irq_table[i].irq) |
144 | break; | ||
145 | } | ||
145 | 146 | ||
146 | spin_lock_irqsave(&irq_action_lock, flags); | ||
147 | if (i < NR_IRQS) { | 147 | if (i < NR_IRQS) { |
148 | action = sparc_irq[i].action; | 148 | irq_table[i].real_irq = real_irq; |
149 | if (!action) | 149 | irq_table[i].irq = i; |
150 | goto out_unlock; | 150 | irq_table[i].pil = pil; |
151 | seq_printf(p, "%3d: ", i); | 151 | } else { |
152 | #ifndef CONFIG_SMP | 152 | printk(KERN_ERR "IRQ: Out of virtual IRQs.\n"); |
153 | seq_printf(p, "%10u ", kstat_irqs(i)); | 153 | i = 0; |
154 | #else | ||
155 | for_each_online_cpu(j) { | ||
156 | seq_printf(p, "%10u ", | ||
157 | kstat_cpu(j).irqs[i]); | ||
158 | } | ||
159 | #endif | ||
160 | seq_printf(p, " %c %s", | ||
161 | (action->flags & IRQF_DISABLED) ? '+' : ' ', | ||
162 | action->name); | ||
163 | for (action = action->next; action; action = action->next) { | ||
164 | seq_printf(p, ",%s %s", | ||
165 | (action->flags & IRQF_DISABLED) ? " +" : "", | ||
166 | action->name); | ||
167 | } | ||
168 | seq_putc(p, '\n'); | ||
169 | } | 154 | } |
170 | out_unlock: | 155 | found: |
171 | spin_unlock_irqrestore(&irq_action_lock, flags); | 156 | spin_unlock_irqrestore(&irq_table_lock, flags); |
172 | return 0; | 157 | |
158 | return i; | ||
173 | } | 159 | } |
174 | 160 | ||
175 | void free_irq(unsigned int irq, void *dev_id) | 161 | /* Based on a single pil handler_irq may need to call several |
162 | * interrupt handlers. Use irq_map as entry to irq_table, | ||
163 | * and let each entry in irq_table point to the next entry. | ||
164 | */ | ||
165 | void irq_link(unsigned int irq) | ||
176 | { | 166 | { |
177 | struct irqaction *action; | 167 | struct irq_bucket *p; |
178 | struct irqaction **actionp; | ||
179 | unsigned long flags; | 168 | unsigned long flags; |
180 | unsigned int cpu_irq; | 169 | unsigned int pil; |
181 | 170 | ||
182 | if (sparc_cpu_model == sun4d) { | 171 | BUG_ON(irq >= NR_IRQS); |
183 | sun4d_free_irq(irq, dev_id); | ||
184 | return; | ||
185 | } | ||
186 | cpu_irq = irq & (NR_IRQS - 1); | ||
187 | if (cpu_irq > 14) { /* 14 irq levels on the sparc */ | ||
188 | printk(KERN_ERR "Trying to free bogus IRQ %d\n", irq); | ||
189 | return; | ||
190 | } | ||
191 | 172 | ||
192 | spin_lock_irqsave(&irq_action_lock, flags); | 173 | spin_lock_irqsave(&irq_map_lock, flags); |
193 | 174 | ||
194 | actionp = &sparc_irq[cpu_irq].action; | 175 | p = &irq_table[irq]; |
195 | action = *actionp; | 176 | pil = p->pil; |
177 | BUG_ON(pil > SUN4D_MAX_IRQ); | ||
178 | p->next = irq_map[pil]; | ||
179 | irq_map[pil] = p; | ||
196 | 180 | ||
197 | if (!action->handler) { | 181 | spin_unlock_irqrestore(&irq_map_lock, flags); |
198 | printk(KERN_ERR "Trying to free free IRQ%d\n", irq); | 182 | } |
199 | goto out_unlock; | ||
200 | } | ||
201 | if (dev_id) { | ||
202 | for (; action; action = action->next) { | ||
203 | if (action->dev_id == dev_id) | ||
204 | break; | ||
205 | actionp = &action->next; | ||
206 | } | ||
207 | if (!action) { | ||
208 | printk(KERN_ERR "Trying to free free shared IRQ%d\n", | ||
209 | irq); | ||
210 | goto out_unlock; | ||
211 | } | ||
212 | } else if (action->flags & IRQF_SHARED) { | ||
213 | printk(KERN_ERR "Trying to free shared IRQ%d with NULL device ID\n", | ||
214 | irq); | ||
215 | goto out_unlock; | ||
216 | } | ||
217 | if (action->flags & SA_STATIC_ALLOC) { | ||
218 | /* | ||
219 | * This interrupt is marked as specially allocated | ||
220 | * so it is a bad idea to free it. | ||
221 | */ | ||
222 | printk(KERN_ERR "Attempt to free statically allocated IRQ%d (%s)\n", | ||
223 | irq, action->name); | ||
224 | goto out_unlock; | ||
225 | } | ||
226 | |||
227 | *actionp = action->next; | ||
228 | |||
229 | spin_unlock_irqrestore(&irq_action_lock, flags); | ||
230 | 183 | ||
231 | synchronize_irq(irq); | 184 | void irq_unlink(unsigned int irq) |
185 | { | ||
186 | struct irq_bucket *p, **pnext; | ||
187 | unsigned long flags; | ||
232 | 188 | ||
233 | spin_lock_irqsave(&irq_action_lock, flags); | 189 | BUG_ON(irq >= NR_IRQS); |
234 | 190 | ||
235 | kfree(action); | 191 | spin_lock_irqsave(&irq_map_lock, flags); |
236 | 192 | ||
237 | if (!sparc_irq[cpu_irq].action) | 193 | p = &irq_table[irq]; |
238 | __disable_irq(irq); | 194 | BUG_ON(p->pil > SUN4D_MAX_IRQ); |
195 | pnext = &irq_map[p->pil]; | ||
196 | while (*pnext != p) | ||
197 | pnext = &(*pnext)->next; | ||
198 | *pnext = p->next; | ||
239 | 199 | ||
240 | out_unlock: | 200 | spin_unlock_irqrestore(&irq_map_lock, flags); |
241 | spin_unlock_irqrestore(&irq_action_lock, flags); | ||
242 | } | 201 | } |
243 | EXPORT_SYMBOL(free_irq); | ||
244 | 202 | ||
245 | /* | ||
246 | * This is called when we want to synchronize with | ||
247 | * interrupts. We may for example tell a device to | ||
248 | * stop sending interrupts: but to make sure there | ||
249 | * are no interrupts that are executing on another | ||
250 | * CPU we need to call this function. | ||
251 | */ | ||
252 | #ifdef CONFIG_SMP | ||
253 | void synchronize_irq(unsigned int irq) | ||
254 | { | ||
255 | unsigned int cpu_irq; | ||
256 | 203 | ||
257 | cpu_irq = irq & (NR_IRQS - 1); | 204 | /* /proc/interrupts printing */ |
258 | while (sparc_irq[cpu_irq].flags & SPARC_IRQ_INPROGRESS) | 205 | int arch_show_interrupts(struct seq_file *p, int prec) |
259 | cpu_relax(); | ||
260 | } | ||
261 | EXPORT_SYMBOL(synchronize_irq); | ||
262 | #endif /* SMP */ | ||
263 | |||
264 | void unexpected_irq(int irq, void *dev_id, struct pt_regs *regs) | ||
265 | { | 206 | { |
266 | int i; | 207 | int j; |
267 | struct irqaction *action; | ||
268 | unsigned int cpu_irq; | ||
269 | 208 | ||
270 | cpu_irq = irq & (NR_IRQS - 1); | 209 | seq_printf(p, "NMI: "); |
271 | action = sparc_irq[cpu_irq].action; | 210 | for_each_online_cpu(j) |
272 | 211 | seq_printf(p, "%10u ", cpu_data(j).counter); | |
273 | printk(KERN_ERR "IO device interrupt, irq = %d\n", irq); | 212 | seq_printf(p, " Non-maskable interrupts\n"); |
274 | printk(KERN_ERR "PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, | 213 | return 0; |
275 | regs->npc, regs->u_regs[14]); | ||
276 | if (action) { | ||
277 | printk(KERN_ERR "Expecting: "); | ||
278 | for (i = 0; i < 16; i++) | ||
279 | if (action->handler) | ||
280 | printk(KERN_CONT "[%s:%d:0x%x] ", action->name, | ||
281 | i, (unsigned int)action->handler); | ||
282 | } | ||
283 | printk(KERN_ERR "AIEEE\n"); | ||
284 | panic("bogus interrupt received"); | ||
285 | } | 214 | } |
286 | 215 | ||
287 | void handler_irq(int pil, struct pt_regs *regs) | 216 | void handler_irq(unsigned int pil, struct pt_regs *regs) |
288 | { | 217 | { |
289 | struct pt_regs *old_regs; | 218 | struct pt_regs *old_regs; |
290 | struct irqaction *action; | 219 | struct irq_bucket *p; |
291 | int cpu = smp_processor_id(); | ||
292 | 220 | ||
221 | BUG_ON(pil > 15); | ||
293 | old_regs = set_irq_regs(regs); | 222 | old_regs = set_irq_regs(regs); |
294 | irq_enter(); | 223 | irq_enter(); |
295 | disable_pil_irq(pil); | 224 | |
296 | #ifdef CONFIG_SMP | 225 | p = irq_map[pil]; |
297 | /* Only rotate on lower priority IRQs (scsi, ethernet, etc.). */ | 226 | while (p) { |
298 | if ((sparc_cpu_model==sun4m) && (pil < 10)) | 227 | struct irq_bucket *next = p->next; |
299 | smp4m_irq_rotate(cpu); | 228 | |
300 | #endif | 229 | generic_handle_irq(p->irq); |
301 | action = sparc_irq[pil].action; | 230 | p = next; |
302 | sparc_irq[pil].flags |= SPARC_IRQ_INPROGRESS; | 231 | } |
303 | kstat_cpu(cpu).irqs[pil]++; | ||
304 | do { | ||
305 | if (!action || !action->handler) | ||
306 | unexpected_irq(pil, NULL, regs); | ||
307 | action->handler(pil, action->dev_id); | ||
308 | action = action->next; | ||
309 | } while (action); | ||
310 | sparc_irq[pil].flags &= ~SPARC_IRQ_INPROGRESS; | ||
311 | enable_pil_irq(pil); | ||
312 | irq_exit(); | 232 | irq_exit(); |
313 | set_irq_regs(old_regs); | 233 | set_irq_regs(old_regs); |
314 | } | 234 | } |
315 | 235 | ||
316 | #if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE) | 236 | #if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE) |
237 | static unsigned int floppy_irq; | ||
317 | 238 | ||
318 | /* | 239 | int sparc_floppy_request_irq(unsigned int irq, irq_handler_t irq_handler) |
319 | * Fast IRQs on the Sparc can only have one routine attached to them, | ||
320 | * thus no sharing possible. | ||
321 | */ | ||
322 | static int request_fast_irq(unsigned int irq, | ||
323 | void (*handler)(void), | ||
324 | unsigned long irqflags, const char *devname) | ||
325 | { | 240 | { |
326 | struct irqaction *action; | ||
327 | unsigned long flags; | ||
328 | unsigned int cpu_irq; | 241 | unsigned int cpu_irq; |
329 | int ret; | 242 | int err; |
243 | |||
330 | #if defined CONFIG_SMP && !defined CONFIG_SPARC_LEON | 244 | #if defined CONFIG_SMP && !defined CONFIG_SPARC_LEON |
331 | struct tt_entry *trap_table; | 245 | struct tt_entry *trap_table; |
332 | #endif | 246 | #endif |
333 | cpu_irq = irq & (NR_IRQS - 1); | ||
334 | if (cpu_irq > 14) { | ||
335 | ret = -EINVAL; | ||
336 | goto out; | ||
337 | } | ||
338 | if (!handler) { | ||
339 | ret = -EINVAL; | ||
340 | goto out; | ||
341 | } | ||
342 | 247 | ||
343 | spin_lock_irqsave(&irq_action_lock, flags); | 248 | err = request_irq(irq, irq_handler, 0, "floppy", NULL); |
249 | if (err) | ||
250 | return -1; | ||
344 | 251 | ||
345 | action = sparc_irq[cpu_irq].action; | 252 | /* Save for later use in floppy interrupt handler */ |
346 | if (action) { | 253 | floppy_irq = irq; |
347 | if (action->flags & IRQF_SHARED) | ||
348 | panic("Trying to register fast irq when already shared.\n"); | ||
349 | if (irqflags & IRQF_SHARED) | ||
350 | panic("Trying to register fast irq as shared.\n"); | ||
351 | 254 | ||
352 | /* Anyway, someone already owns it so cannot be made fast. */ | 255 | cpu_irq = (irq & (NR_IRQS - 1)); |
353 | printk(KERN_ERR "request_fast_irq: Trying to register yet already owned.\n"); | ||
354 | ret = -EBUSY; | ||
355 | goto out_unlock; | ||
356 | } | ||
357 | |||
358 | /* | ||
359 | * If this is flagged as statically allocated then we use our | ||
360 | * private struct which is never freed. | ||
361 | */ | ||
362 | if (irqflags & SA_STATIC_ALLOC) { | ||
363 | if (static_irq_count < MAX_STATIC_ALLOC) | ||
364 | action = &static_irqaction[static_irq_count++]; | ||
365 | else | ||
366 | printk(KERN_ERR "Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n", | ||
367 | irq, devname); | ||
368 | } | ||
369 | |||
370 | if (action == NULL) | ||
371 | action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC); | ||
372 | if (!action) { | ||
373 | ret = -ENOMEM; | ||
374 | goto out_unlock; | ||
375 | } | ||
376 | 256 | ||
377 | /* Dork with trap table if we get this far. */ | 257 | /* Dork with trap table if we get this far. */ |
378 | #define INSTANTIATE(table) \ | 258 | #define INSTANTIATE(table) \ |
379 | table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_one = SPARC_RD_PSR_L0; \ | 259 | table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_one = SPARC_RD_PSR_L0; \ |
380 | table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two = \ | 260 | table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two = \ |
381 | SPARC_BRANCH((unsigned long) handler, \ | 261 | SPARC_BRANCH((unsigned long) floppy_hardint, \ |
382 | (unsigned long) &table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two);\ | 262 | (unsigned long) &table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two);\ |
383 | table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_three = SPARC_RD_WIM_L3; \ | 263 | table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_three = SPARC_RD_WIM_L3; \ |
384 | table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP; | 264 | table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP; |
@@ -399,22 +279,9 @@ static int request_fast_irq(unsigned int irq, | |||
399 | * writing we have no CPU-neutral interface to fine-grained flushes. | 279 | * writing we have no CPU-neutral interface to fine-grained flushes. |
400 | */ | 280 | */ |
401 | flush_cache_all(); | 281 | flush_cache_all(); |
402 | 282 | return 0; | |
403 | action->flags = irqflags; | ||
404 | action->name = devname; | ||
405 | action->dev_id = NULL; | ||
406 | action->next = NULL; | ||
407 | |||
408 | sparc_irq[cpu_irq].action = action; | ||
409 | |||
410 | __enable_irq(irq); | ||
411 | |||
412 | ret = 0; | ||
413 | out_unlock: | ||
414 | spin_unlock_irqrestore(&irq_action_lock, flags); | ||
415 | out: | ||
416 | return ret; | ||
417 | } | 283 | } |
284 | EXPORT_SYMBOL(sparc_floppy_request_irq); | ||
418 | 285 | ||
419 | /* | 286 | /* |
420 | * These variables are used to access state from the assembler | 287 | * These variables are used to access state from the assembler |
@@ -440,154 +307,23 @@ EXPORT_SYMBOL(pdma_base); | |||
440 | unsigned long pdma_areasize; | 307 | unsigned long pdma_areasize; |
441 | EXPORT_SYMBOL(pdma_areasize); | 308 | EXPORT_SYMBOL(pdma_areasize); |
442 | 309 | ||
443 | static irq_handler_t floppy_irq_handler; | 310 | /* Use the generic irq support to call floppy_interrupt |
444 | 311 | * which was setup using request_irq() in sparc_floppy_request_irq(). | |
312 | * We only have one floppy interrupt so we do not need to check | ||
313 | * for additional handlers being wired up by irq_link() | ||
314 | */ | ||
445 | void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) | 315 | void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) |
446 | { | 316 | { |
447 | struct pt_regs *old_regs; | 317 | struct pt_regs *old_regs; |
448 | int cpu = smp_processor_id(); | ||
449 | 318 | ||
450 | old_regs = set_irq_regs(regs); | 319 | old_regs = set_irq_regs(regs); |
451 | disable_pil_irq(irq); | ||
452 | irq_enter(); | 320 | irq_enter(); |
453 | kstat_cpu(cpu).irqs[irq]++; | 321 | generic_handle_irq(floppy_irq); |
454 | floppy_irq_handler(irq, dev_id); | ||
455 | irq_exit(); | 322 | irq_exit(); |
456 | enable_pil_irq(irq); | ||
457 | set_irq_regs(old_regs); | 323 | set_irq_regs(old_regs); |
458 | /* | ||
459 | * XXX Eek, it's totally changed with preempt_count() and such | ||
460 | * if (softirq_pending(cpu)) | ||
461 | * do_softirq(); | ||
462 | */ | ||
463 | } | 324 | } |
464 | |||
465 | int sparc_floppy_request_irq(int irq, unsigned long flags, | ||
466 | irq_handler_t irq_handler) | ||
467 | { | ||
468 | floppy_irq_handler = irq_handler; | ||
469 | return request_fast_irq(irq, floppy_hardint, flags, "floppy"); | ||
470 | } | ||
471 | EXPORT_SYMBOL(sparc_floppy_request_irq); | ||
472 | |||
473 | #endif | 325 | #endif |
474 | 326 | ||
475 | int request_irq(unsigned int irq, | ||
476 | irq_handler_t handler, | ||
477 | unsigned long irqflags, const char *devname, void *dev_id) | ||
478 | { | ||
479 | struct irqaction *action, **actionp; | ||
480 | unsigned long flags; | ||
481 | unsigned int cpu_irq; | ||
482 | int ret; | ||
483 | |||
484 | if (sparc_cpu_model == sun4d) | ||
485 | return sun4d_request_irq(irq, handler, irqflags, devname, dev_id); | ||
486 | |||
487 | cpu_irq = irq & (NR_IRQS - 1); | ||
488 | if (cpu_irq > 14) { | ||
489 | ret = -EINVAL; | ||
490 | goto out; | ||
491 | } | ||
492 | if (!handler) { | ||
493 | ret = -EINVAL; | ||
494 | goto out; | ||
495 | } | ||
496 | |||
497 | spin_lock_irqsave(&irq_action_lock, flags); | ||
498 | |||
499 | actionp = &sparc_irq[cpu_irq].action; | ||
500 | action = *actionp; | ||
501 | if (action) { | ||
502 | if (!(action->flags & IRQF_SHARED) || !(irqflags & IRQF_SHARED)) { | ||
503 | ret = -EBUSY; | ||
504 | goto out_unlock; | ||
505 | } | ||
506 | if ((action->flags & IRQF_DISABLED) != (irqflags & IRQF_DISABLED)) { | ||
507 | printk(KERN_ERR "Attempt to mix fast and slow interrupts on IRQ%d denied\n", | ||
508 | irq); | ||
509 | ret = -EBUSY; | ||
510 | goto out_unlock; | ||
511 | } | ||
512 | for ( ; action; action = *actionp) | ||
513 | actionp = &action->next; | ||
514 | } | ||
515 | |||
516 | /* If this is flagged as statically allocated then we use our | ||
517 | * private struct which is never freed. | ||
518 | */ | ||
519 | if (irqflags & SA_STATIC_ALLOC) { | ||
520 | if (static_irq_count < MAX_STATIC_ALLOC) | ||
521 | action = &static_irqaction[static_irq_count++]; | ||
522 | else | ||
523 | printk(KERN_ERR "Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n", | ||
524 | irq, devname); | ||
525 | } | ||
526 | if (action == NULL) | ||
527 | action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC); | ||
528 | if (!action) { | ||
529 | ret = -ENOMEM; | ||
530 | goto out_unlock; | ||
531 | } | ||
532 | |||
533 | action->handler = handler; | ||
534 | action->flags = irqflags; | ||
535 | action->name = devname; | ||
536 | action->next = NULL; | ||
537 | action->dev_id = dev_id; | ||
538 | |||
539 | *actionp = action; | ||
540 | |||
541 | __enable_irq(irq); | ||
542 | |||
543 | ret = 0; | ||
544 | out_unlock: | ||
545 | spin_unlock_irqrestore(&irq_action_lock, flags); | ||
546 | out: | ||
547 | return ret; | ||
548 | } | ||
549 | EXPORT_SYMBOL(request_irq); | ||
550 | |||
551 | void disable_irq_nosync(unsigned int irq) | ||
552 | { | ||
553 | __disable_irq(irq); | ||
554 | } | ||
555 | EXPORT_SYMBOL(disable_irq_nosync); | ||
556 | |||
557 | void disable_irq(unsigned int irq) | ||
558 | { | ||
559 | __disable_irq(irq); | ||
560 | } | ||
561 | EXPORT_SYMBOL(disable_irq); | ||
562 | |||
563 | void enable_irq(unsigned int irq) | ||
564 | { | ||
565 | __enable_irq(irq); | ||
566 | } | ||
567 | EXPORT_SYMBOL(enable_irq); | ||
568 | |||
569 | /* | ||
570 | * We really don't need these at all on the Sparc. We only have | ||
571 | * stubs here because they are exported to modules. | ||
572 | */ | ||
573 | unsigned long probe_irq_on(void) | ||
574 | { | ||
575 | return 0; | ||
576 | } | ||
577 | EXPORT_SYMBOL(probe_irq_on); | ||
578 | |||
579 | int probe_irq_off(unsigned long mask) | ||
580 | { | ||
581 | return 0; | ||
582 | } | ||
583 | EXPORT_SYMBOL(probe_irq_off); | ||
584 | |||
585 | static unsigned int build_device_irq(struct platform_device *op, | ||
586 | unsigned int real_irq) | ||
587 | { | ||
588 | return real_irq; | ||
589 | } | ||
590 | |||
591 | /* djhr | 327 | /* djhr |
592 | * This could probably be made indirect too and assigned in the CPU | 328 | * This could probably be made indirect too and assigned in the CPU |
593 | * bits of the code. That would be much nicer I think and would also | 329 | * bits of the code. That would be much nicer I think and would also |
@@ -598,8 +334,6 @@ static unsigned int build_device_irq(struct platform_device *op, | |||
598 | 334 | ||
599 | void __init init_IRQ(void) | 335 | void __init init_IRQ(void) |
600 | { | 336 | { |
601 | sparc_irq_config.build_device_irq = build_device_irq; | ||
602 | |||
603 | switch (sparc_cpu_model) { | 337 | switch (sparc_cpu_model) { |
604 | case sun4c: | 338 | case sun4c: |
605 | case sun4: | 339 | case sun4: |
@@ -629,9 +363,3 @@ void __init init_IRQ(void) | |||
629 | btfixup(); | 363 | btfixup(); |
630 | } | 364 | } |
631 | 365 | ||
632 | #ifdef CONFIG_PROC_FS | ||
633 | void init_irq_proc(void) | ||
634 | { | ||
635 | /* For now, nothing... */ | ||
636 | } | ||
637 | #endif /* CONFIG_PROC_FS */ | ||
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index 24ad449886be..487d67a4e7f6 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h | |||
@@ -37,6 +37,7 @@ extern void sun4c_init_IRQ(void); | |||
37 | extern unsigned int lvl14_resolution; | 37 | extern unsigned int lvl14_resolution; |
38 | 38 | ||
39 | extern void sun4m_init_IRQ(void); | 39 | extern void sun4m_init_IRQ(void); |
40 | extern void sun4m_unmask_profile_irq(void); | ||
40 | extern void sun4m_clear_profile_irq(int cpu); | 41 | extern void sun4m_clear_profile_irq(int cpu); |
41 | 42 | ||
42 | /* sun4d_irq.c */ | 43 | /* sun4d_irq.c */ |
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 2969f777fa11..8591cf124ecf 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c | |||
@@ -83,20 +83,22 @@ static inline unsigned long get_irqmask(unsigned int irq) | |||
83 | return mask; | 83 | return mask; |
84 | } | 84 | } |
85 | 85 | ||
86 | static void leon_enable_irq(unsigned int irq_nr) | 86 | static void leon_unmask_irq(struct irq_data *data) |
87 | { | 87 | { |
88 | unsigned long mask, flags; | 88 | unsigned long mask, flags; |
89 | mask = get_irqmask(irq_nr); | 89 | |
90 | mask = (unsigned long)data->chip_data; | ||
90 | local_irq_save(flags); | 91 | local_irq_save(flags); |
91 | LEON3_BYPASS_STORE_PA(LEON_IMASK, | 92 | LEON3_BYPASS_STORE_PA(LEON_IMASK, |
92 | (LEON3_BYPASS_LOAD_PA(LEON_IMASK) | (mask))); | 93 | (LEON3_BYPASS_LOAD_PA(LEON_IMASK) | (mask))); |
93 | local_irq_restore(flags); | 94 | local_irq_restore(flags); |
94 | } | 95 | } |
95 | 96 | ||
96 | static void leon_disable_irq(unsigned int irq_nr) | 97 | static void leon_mask_irq(struct irq_data *data) |
97 | { | 98 | { |
98 | unsigned long mask, flags; | 99 | unsigned long mask, flags; |
99 | mask = get_irqmask(irq_nr); | 100 | |
101 | mask = (unsigned long)data->chip_data; | ||
100 | local_irq_save(flags); | 102 | local_irq_save(flags); |
101 | LEON3_BYPASS_STORE_PA(LEON_IMASK, | 103 | LEON3_BYPASS_STORE_PA(LEON_IMASK, |
102 | (LEON3_BYPASS_LOAD_PA(LEON_IMASK) & ~(mask))); | 104 | (LEON3_BYPASS_LOAD_PA(LEON_IMASK) & ~(mask))); |
@@ -104,6 +106,50 @@ static void leon_disable_irq(unsigned int irq_nr) | |||
104 | 106 | ||
105 | } | 107 | } |
106 | 108 | ||
109 | static unsigned int leon_startup_irq(struct irq_data *data) | ||
110 | { | ||
111 | irq_link(data->irq); | ||
112 | leon_unmask_irq(data); | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static void leon_shutdown_irq(struct irq_data *data) | ||
117 | { | ||
118 | leon_mask_irq(data); | ||
119 | irq_unlink(data->irq); | ||
120 | } | ||
121 | |||
122 | static struct irq_chip leon_irq = { | ||
123 | .name = "leon", | ||
124 | .irq_startup = leon_startup_irq, | ||
125 | .irq_shutdown = leon_shutdown_irq, | ||
126 | .irq_mask = leon_mask_irq, | ||
127 | .irq_unmask = leon_unmask_irq, | ||
128 | }; | ||
129 | |||
130 | static unsigned int leon_build_device_irq(struct platform_device *op, | ||
131 | unsigned int real_irq) | ||
132 | { | ||
133 | unsigned int irq; | ||
134 | unsigned long mask; | ||
135 | |||
136 | irq = 0; | ||
137 | mask = get_irqmask(real_irq); | ||
138 | if (mask == 0) | ||
139 | goto out; | ||
140 | |||
141 | irq = irq_alloc(real_irq, real_irq); | ||
142 | if (irq == 0) | ||
143 | goto out; | ||
144 | |||
145 | irq_set_chip_and_handler_name(irq, &leon_irq, | ||
146 | handle_simple_irq, "edge"); | ||
147 | irq_set_chip_data(irq, (void *)mask); | ||
148 | |||
149 | out: | ||
150 | return irq; | ||
151 | } | ||
152 | |||
107 | void __init leon_init_timers(irq_handler_t counter_fn) | 153 | void __init leon_init_timers(irq_handler_t counter_fn) |
108 | { | 154 | { |
109 | int irq; | 155 | int irq; |
@@ -112,6 +158,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
112 | int len; | 158 | int len; |
113 | int cpu, icsel; | 159 | int cpu, icsel; |
114 | int ampopts; | 160 | int ampopts; |
161 | int err; | ||
115 | 162 | ||
116 | leondebug_irq_disable = 0; | 163 | leondebug_irq_disable = 0; |
117 | leon_debug_irqout = 0; | 164 | leon_debug_irqout = 0; |
@@ -219,11 +266,10 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
219 | goto bad; | 266 | goto bad; |
220 | } | 267 | } |
221 | 268 | ||
222 | irq = request_irq(leon3_gptimer_irq+leon3_gptimer_idx, | 269 | irq = leon_build_device_irq(NULL, leon3_gptimer_irq + leon3_gptimer_idx); |
223 | counter_fn, | 270 | err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); |
224 | (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); | ||
225 | 271 | ||
226 | if (irq) { | 272 | if (err) { |
227 | printk(KERN_ERR "leon_time_init: unable to attach IRQ%d\n", | 273 | printk(KERN_ERR "leon_time_init: unable to attach IRQ%d\n", |
228 | LEON_INTERRUPT_TIMER1); | 274 | LEON_INTERRUPT_TIMER1); |
229 | prom_halt(); | 275 | prom_halt(); |
@@ -347,12 +393,8 @@ void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu) | |||
347 | 393 | ||
348 | void __init leon_init_IRQ(void) | 394 | void __init leon_init_IRQ(void) |
349 | { | 395 | { |
350 | sparc_irq_config.init_timers = leon_init_timers; | 396 | sparc_irq_config.init_timers = leon_init_timers; |
351 | 397 | sparc_irq_config.build_device_irq = leon_build_device_irq; | |
352 | BTFIXUPSET_CALL(enable_irq, leon_enable_irq, BTFIXUPCALL_NORM); | ||
353 | BTFIXUPSET_CALL(disable_irq, leon_disable_irq, BTFIXUPCALL_NORM); | ||
354 | BTFIXUPSET_CALL(enable_pil_irq, leon_enable_irq, BTFIXUPCALL_NORM); | ||
355 | BTFIXUPSET_CALL(disable_pil_irq, leon_disable_irq, BTFIXUPCALL_NORM); | ||
356 | 398 | ||
357 | BTFIXUPSET_CALL(clear_clock_irq, leon_clear_clock_irq, | 399 | BTFIXUPSET_CALL(clear_clock_irq, leon_clear_clock_irq, |
358 | BTFIXUPCALL_NORM); | 400 | BTFIXUPCALL_NORM); |
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 2cdc131b50ac..948601a066ff 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c | |||
@@ -164,6 +164,9 @@ void __iomem *pcic_regs; | |||
164 | volatile int pcic_speculative; | 164 | volatile int pcic_speculative; |
165 | volatile int pcic_trapped; | 165 | volatile int pcic_trapped; |
166 | 166 | ||
167 | /* forward */ | ||
168 | unsigned int pcic_build_device_irq(struct platform_device *op, | ||
169 | unsigned int real_irq); | ||
167 | 170 | ||
168 | #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3)) | 171 | #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3)) |
169 | 172 | ||
@@ -523,6 +526,7 @@ static void | |||
523 | pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) | 526 | pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) |
524 | { | 527 | { |
525 | struct pcic_ca2irq *p; | 528 | struct pcic_ca2irq *p; |
529 | unsigned int real_irq; | ||
526 | int i, ivec; | 530 | int i, ivec; |
527 | char namebuf[64]; | 531 | char namebuf[64]; |
528 | 532 | ||
@@ -551,26 +555,25 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) | |||
551 | i = p->pin; | 555 | i = p->pin; |
552 | if (i >= 0 && i < 4) { | 556 | if (i >= 0 && i < 4) { |
553 | ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO); | 557 | ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO); |
554 | dev->irq = ivec >> (i << 2) & 0xF; | 558 | real_irq = ivec >> (i << 2) & 0xF; |
555 | } else if (i >= 4 && i < 8) { | 559 | } else if (i >= 4 && i < 8) { |
556 | ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI); | 560 | ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI); |
557 | dev->irq = ivec >> ((i-4) << 2) & 0xF; | 561 | real_irq = ivec >> ((i-4) << 2) & 0xF; |
558 | } else { /* Corrupted map */ | 562 | } else { /* Corrupted map */ |
559 | printk("PCIC: BAD PIN %d\n", i); for (;;) {} | 563 | printk("PCIC: BAD PIN %d\n", i); for (;;) {} |
560 | } | 564 | } |
561 | /* P3 */ /* printk("PCIC: device %s pin %d ivec 0x%x irq %x\n", namebuf, i, ivec, dev->irq); */ | 565 | /* P3 */ /* printk("PCIC: device %s pin %d ivec 0x%x irq %x\n", namebuf, i, ivec, dev->irq); */ |
562 | 566 | ||
563 | /* | 567 | /* real_irq means PROM did not bother to program the upper |
564 | * dev->irq=0 means PROM did not bother to program the upper | ||
565 | * half of PCIC. This happens on JS-E with PROM 3.11, for instance. | 568 | * half of PCIC. This happens on JS-E with PROM 3.11, for instance. |
566 | */ | 569 | */ |
567 | if (dev->irq == 0 || p->force) { | 570 | if (real_irq == 0 || p->force) { |
568 | if (p->irq == 0 || p->irq >= 15) { /* Corrupted map */ | 571 | if (p->irq == 0 || p->irq >= 15) { /* Corrupted map */ |
569 | printk("PCIC: BAD IRQ %d\n", p->irq); for (;;) {} | 572 | printk("PCIC: BAD IRQ %d\n", p->irq); for (;;) {} |
570 | } | 573 | } |
571 | printk("PCIC: setting irq %d at pin %d for device %02x:%02x\n", | 574 | printk("PCIC: setting irq %d at pin %d for device %02x:%02x\n", |
572 | p->irq, p->pin, dev->bus->number, dev->devfn); | 575 | p->irq, p->pin, dev->bus->number, dev->devfn); |
573 | dev->irq = p->irq; | 576 | real_irq = p->irq; |
574 | 577 | ||
575 | i = p->pin; | 578 | i = p->pin; |
576 | if (i >= 4) { | 579 | if (i >= 4) { |
@@ -584,7 +587,8 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) | |||
584 | ivec |= p->irq << (i << 2); | 587 | ivec |= p->irq << (i << 2); |
585 | writew(ivec, pcic->pcic_regs+PCI_INT_SELECT_LO); | 588 | writew(ivec, pcic->pcic_regs+PCI_INT_SELECT_LO); |
586 | } | 589 | } |
587 | } | 590 | } |
591 | dev->irq = pcic_build_device_irq(NULL, real_irq); | ||
588 | } | 592 | } |
589 | 593 | ||
590 | /* | 594 | /* |
@@ -729,6 +733,7 @@ void __init pci_time_init(void) | |||
729 | struct linux_pcic *pcic = &pcic0; | 733 | struct linux_pcic *pcic = &pcic0; |
730 | unsigned long v; | 734 | unsigned long v; |
731 | int timer_irq, irq; | 735 | int timer_irq, irq; |
736 | int err; | ||
732 | 737 | ||
733 | do_arch_gettimeoffset = pci_gettimeoffset; | 738 | do_arch_gettimeoffset = pci_gettimeoffset; |
734 | 739 | ||
@@ -740,9 +745,10 @@ void __init pci_time_init(void) | |||
740 | timer_irq = PCI_COUNTER_IRQ_SYS(v); | 745 | timer_irq = PCI_COUNTER_IRQ_SYS(v); |
741 | writel (PCI_COUNTER_IRQ_SET(timer_irq, 0), | 746 | writel (PCI_COUNTER_IRQ_SET(timer_irq, 0), |
742 | pcic->pcic_regs+PCI_COUNTER_IRQ); | 747 | pcic->pcic_regs+PCI_COUNTER_IRQ); |
743 | irq = request_irq(timer_irq, pcic_timer_handler, | 748 | irq = pcic_build_device_irq(NULL, timer_irq); |
744 | (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); | 749 | err = request_irq(irq, pcic_timer_handler, |
745 | if (irq) { | 750 | IRQF_TIMER, "timer", NULL); |
751 | if (err) { | ||
746 | prom_printf("time_init: unable to attach IRQ%d\n", timer_irq); | 752 | prom_printf("time_init: unable to attach IRQ%d\n", timer_irq); |
747 | prom_halt(); | 753 | prom_halt(); |
748 | } | 754 | } |
@@ -803,50 +809,73 @@ static inline unsigned long get_irqmask(int irq_nr) | |||
803 | return 1 << irq_nr; | 809 | return 1 << irq_nr; |
804 | } | 810 | } |
805 | 811 | ||
806 | static void pcic_disable_irq(unsigned int irq_nr) | 812 | static void pcic_mask_irq(struct irq_data *data) |
807 | { | 813 | { |
808 | unsigned long mask, flags; | 814 | unsigned long mask, flags; |
809 | 815 | ||
810 | mask = get_irqmask(irq_nr); | 816 | mask = (unsigned long)data->chip_data; |
811 | local_irq_save(flags); | 817 | local_irq_save(flags); |
812 | writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); | 818 | writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); |
813 | local_irq_restore(flags); | 819 | local_irq_restore(flags); |
814 | } | 820 | } |
815 | 821 | ||
816 | static void pcic_enable_irq(unsigned int irq_nr) | 822 | static void pcic_unmask_irq(struct irq_data *data) |
817 | { | 823 | { |
818 | unsigned long mask, flags; | 824 | unsigned long mask, flags; |
819 | 825 | ||
820 | mask = get_irqmask(irq_nr); | 826 | mask = (unsigned long)data->chip_data; |
821 | local_irq_save(flags); | 827 | local_irq_save(flags); |
822 | writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); | 828 | writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); |
823 | local_irq_restore(flags); | 829 | local_irq_restore(flags); |
824 | } | 830 | } |
825 | 831 | ||
826 | static void pcic_load_profile_irq(int cpu, unsigned int limit) | 832 | static unsigned int pcic_startup_irq(struct irq_data *data) |
827 | { | 833 | { |
828 | printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__); | 834 | irq_link(data->irq); |
835 | pcic_unmask_irq(data); | ||
836 | return 0; | ||
829 | } | 837 | } |
830 | 838 | ||
831 | /* We assume the caller has disabled local interrupts when these are called, | 839 | static struct irq_chip pcic_irq = { |
832 | * or else very bizarre behavior will result. | 840 | .name = "pcic", |
833 | */ | 841 | .irq_startup = pcic_startup_irq, |
834 | static void pcic_disable_pil_irq(unsigned int pil) | 842 | .irq_mask = pcic_mask_irq, |
843 | .irq_unmask = pcic_unmask_irq, | ||
844 | }; | ||
845 | |||
846 | unsigned int pcic_build_device_irq(struct platform_device *op, | ||
847 | unsigned int real_irq) | ||
835 | { | 848 | { |
836 | writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); | 849 | unsigned int irq; |
850 | unsigned long mask; | ||
851 | |||
852 | irq = 0; | ||
853 | mask = get_irqmask(real_irq); | ||
854 | if (mask == 0) | ||
855 | goto out; | ||
856 | |||
857 | irq = irq_alloc(real_irq, real_irq); | ||
858 | if (irq == 0) | ||
859 | goto out; | ||
860 | |||
861 | irq_set_chip_and_handler_name(irq, &pcic_irq, | ||
862 | handle_level_irq, "PCIC"); | ||
863 | irq_set_chip_data(irq, (void *)mask); | ||
864 | |||
865 | out: | ||
866 | return irq; | ||
837 | } | 867 | } |
838 | 868 | ||
839 | static void pcic_enable_pil_irq(unsigned int pil) | 869 | |
870 | static void pcic_load_profile_irq(int cpu, unsigned int limit) | ||
840 | { | 871 | { |
841 | writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); | 872 | printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__); |
842 | } | 873 | } |
843 | 874 | ||
844 | void __init sun4m_pci_init_IRQ(void) | 875 | void __init sun4m_pci_init_IRQ(void) |
845 | { | 876 | { |
846 | BTFIXUPSET_CALL(enable_irq, pcic_enable_irq, BTFIXUPCALL_NORM); | 877 | sparc_irq_config.build_device_irq = pcic_build_device_irq; |
847 | BTFIXUPSET_CALL(disable_irq, pcic_disable_irq, BTFIXUPCALL_NORM); | 878 | |
848 | BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM); | ||
849 | BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM); | ||
850 | BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); | 879 | BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); |
851 | BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); | 880 | BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); |
852 | } | 881 | } |
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c index 90eea38ad66f..f6bf25a2ff80 100644 --- a/arch/sparc/kernel/sun4c_irq.c +++ b/arch/sparc/kernel/sun4c_irq.c | |||
@@ -65,62 +65,94 @@ | |||
65 | */ | 65 | */ |
66 | unsigned char __iomem *interrupt_enable; | 66 | unsigned char __iomem *interrupt_enable; |
67 | 67 | ||
68 | static void sun4c_disable_irq(unsigned int irq_nr) | 68 | static void sun4c_mask_irq(struct irq_data *data) |
69 | { | 69 | { |
70 | unsigned long flags; | 70 | unsigned long mask = (unsigned long)data->chip_data; |
71 | unsigned char current_mask, new_mask; | 71 | |
72 | 72 | if (mask) { | |
73 | local_irq_save(flags); | 73 | unsigned long flags; |
74 | irq_nr &= (NR_IRQS - 1); | 74 | |
75 | current_mask = sbus_readb(interrupt_enable); | 75 | local_irq_save(flags); |
76 | switch (irq_nr) { | 76 | mask = sbus_readb(interrupt_enable) & ~mask; |
77 | case 1: | 77 | sbus_writeb(mask, interrupt_enable); |
78 | new_mask = ((current_mask) & (~(SUN4C_INT_E1))); | ||
79 | break; | ||
80 | case 8: | ||
81 | new_mask = ((current_mask) & (~(SUN4C_INT_E8))); | ||
82 | break; | ||
83 | case 10: | ||
84 | new_mask = ((current_mask) & (~(SUN4C_INT_E10))); | ||
85 | break; | ||
86 | case 14: | ||
87 | new_mask = ((current_mask) & (~(SUN4C_INT_E14))); | ||
88 | break; | ||
89 | default: | ||
90 | local_irq_restore(flags); | 78 | local_irq_restore(flags); |
91 | return; | ||
92 | } | 79 | } |
93 | sbus_writeb(new_mask, interrupt_enable); | ||
94 | local_irq_restore(flags); | ||
95 | } | 80 | } |
96 | 81 | ||
97 | static void sun4c_enable_irq(unsigned int irq_nr) | 82 | static void sun4c_unmask_irq(struct irq_data *data) |
98 | { | 83 | { |
99 | unsigned long flags; | 84 | unsigned long mask = (unsigned long)data->chip_data; |
100 | unsigned char current_mask, new_mask; | 85 | |
101 | 86 | if (mask) { | |
102 | local_irq_save(flags); | 87 | unsigned long flags; |
103 | irq_nr &= (NR_IRQS - 1); | 88 | |
104 | current_mask = sbus_readb(interrupt_enable); | 89 | local_irq_save(flags); |
105 | switch (irq_nr) { | 90 | mask = sbus_readb(interrupt_enable) | mask; |
106 | case 1: | 91 | sbus_writeb(mask, interrupt_enable); |
107 | new_mask = ((current_mask) | SUN4C_INT_E1); | ||
108 | break; | ||
109 | case 8: | ||
110 | new_mask = ((current_mask) | SUN4C_INT_E8); | ||
111 | break; | ||
112 | case 10: | ||
113 | new_mask = ((current_mask) | SUN4C_INT_E10); | ||
114 | break; | ||
115 | case 14: | ||
116 | new_mask = ((current_mask) | SUN4C_INT_E14); | ||
117 | break; | ||
118 | default: | ||
119 | local_irq_restore(flags); | 92 | local_irq_restore(flags); |
120 | return; | ||
121 | } | 93 | } |
122 | sbus_writeb(new_mask, interrupt_enable); | 94 | } |
123 | local_irq_restore(flags); | 95 | |
96 | static unsigned int sun4c_startup_irq(struct irq_data *data) | ||
97 | { | ||
98 | irq_link(data->irq); | ||
99 | sun4c_unmask_irq(data); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static void sun4c_shutdown_irq(struct irq_data *data) | ||
105 | { | ||
106 | sun4c_mask_irq(data); | ||
107 | irq_unlink(data->irq); | ||
108 | } | ||
109 | |||
110 | static struct irq_chip sun4c_irq = { | ||
111 | .name = "sun4c", | ||
112 | .irq_startup = sun4c_startup_irq, | ||
113 | .irq_shutdown = sun4c_shutdown_irq, | ||
114 | .irq_mask = sun4c_mask_irq, | ||
115 | .irq_unmask = sun4c_unmask_irq, | ||
116 | }; | ||
117 | |||
118 | static unsigned int sun4c_build_device_irq(struct platform_device *op, | ||
119 | unsigned int real_irq) | ||
120 | { | ||
121 | unsigned int irq; | ||
122 | |||
123 | if (real_irq >= 16) { | ||
124 | prom_printf("Bogus sun4c IRQ %u\n", real_irq); | ||
125 | prom_halt(); | ||
126 | } | ||
127 | |||
128 | irq = irq_alloc(real_irq, real_irq); | ||
129 | if (irq) { | ||
130 | unsigned long mask = 0UL; | ||
131 | |||
132 | switch (real_irq) { | ||
133 | case 1: | ||
134 | mask = SUN4C_INT_E1; | ||
135 | break; | ||
136 | case 8: | ||
137 | mask = SUN4C_INT_E8; | ||
138 | break; | ||
139 | case 10: | ||
140 | mask = SUN4C_INT_E10; | ||
141 | break; | ||
142 | case 14: | ||
143 | mask = SUN4C_INT_E14; | ||
144 | break; | ||
145 | default: | ||
146 | /* All the rest are either always enabled, | ||
147 | * or are for signalling software interrupts. | ||
148 | */ | ||
149 | break; | ||
150 | } | ||
151 | irq_set_chip_and_handler_name(irq, &sun4c_irq, | ||
152 | handle_level_irq, "level"); | ||
153 | irq_set_chip_data(irq, (void *)mask); | ||
154 | } | ||
155 | return irq; | ||
124 | } | 156 | } |
125 | 157 | ||
126 | struct sun4c_timer_info { | 158 | struct sun4c_timer_info { |
@@ -144,8 +176,9 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit) | |||
144 | 176 | ||
145 | static void __init sun4c_init_timers(irq_handler_t counter_fn) | 177 | static void __init sun4c_init_timers(irq_handler_t counter_fn) |
146 | { | 178 | { |
147 | const struct linux_prom_irqs *irq; | 179 | const struct linux_prom_irqs *prom_irqs; |
148 | struct device_node *dp; | 180 | struct device_node *dp; |
181 | unsigned int irq; | ||
149 | const u32 *addr; | 182 | const u32 *addr; |
150 | int err; | 183 | int err; |
151 | 184 | ||
@@ -163,9 +196,9 @@ static void __init sun4c_init_timers(irq_handler_t counter_fn) | |||
163 | 196 | ||
164 | sun4c_timers = (void __iomem *) (unsigned long) addr[0]; | 197 | sun4c_timers = (void __iomem *) (unsigned long) addr[0]; |
165 | 198 | ||
166 | irq = of_get_property(dp, "intr", NULL); | 199 | prom_irqs = of_get_property(dp, "intr", NULL); |
167 | of_node_put(dp); | 200 | of_node_put(dp); |
168 | if (!irq) { | 201 | if (!prom_irqs) { |
169 | prom_printf("sun4c_init_timers: No intr property\n"); | 202 | prom_printf("sun4c_init_timers: No intr property\n"); |
170 | prom_halt(); | 203 | prom_halt(); |
171 | } | 204 | } |
@@ -178,15 +211,15 @@ static void __init sun4c_init_timers(irq_handler_t counter_fn) | |||
178 | 211 | ||
179 | master_l10_counter = &sun4c_timers->l10_count; | 212 | master_l10_counter = &sun4c_timers->l10_count; |
180 | 213 | ||
181 | err = request_irq(irq[0].pri, counter_fn, | 214 | irq = sun4c_build_device_irq(NULL, prom_irqs[0].pri); |
182 | (IRQF_DISABLED | SA_STATIC_ALLOC), | 215 | err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); |
183 | "timer", NULL); | ||
184 | if (err) { | 216 | if (err) { |
185 | prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err); | 217 | prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err); |
186 | prom_halt(); | 218 | prom_halt(); |
187 | } | 219 | } |
188 | 220 | ||
189 | sun4c_disable_irq(irq[1].pri); | 221 | /* disable timer interrupt */ |
222 | sun4c_mask_irq(irq_get_irq_data(irq)); | ||
190 | } | 223 | } |
191 | 224 | ||
192 | #ifdef CONFIG_SMP | 225 | #ifdef CONFIG_SMP |
@@ -215,14 +248,11 @@ void __init sun4c_init_IRQ(void) | |||
215 | 248 | ||
216 | interrupt_enable = (void __iomem *) (unsigned long) addr[0]; | 249 | interrupt_enable = (void __iomem *) (unsigned long) addr[0]; |
217 | 250 | ||
218 | BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); | ||
219 | BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); | ||
220 | BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); | ||
221 | BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); | ||
222 | BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); | 251 | BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); |
223 | BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); | 252 | BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); |
224 | 253 | ||
225 | sparc_irq_config.init_timers = sun4c_init_timers; | 254 | sparc_irq_config.init_timers = sun4c_init_timers; |
255 | sparc_irq_config.build_device_irq = sun4c_build_device_irq; | ||
226 | 256 | ||
227 | #ifdef CONFIG_SMP | 257 | #ifdef CONFIG_SMP |
228 | BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); | 258 | BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); |
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index ee35c45ffb89..14a043531dcb 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c | |||
@@ -22,22 +22,20 @@ | |||
22 | * cpu local. CPU local interrupts cover the timer interrupts | 22 | * cpu local. CPU local interrupts cover the timer interrupts |
23 | * and whatnot, and we encode those as normal PILs between | 23 | * and whatnot, and we encode those as normal PILs between |
24 | * 0 and 15. | 24 | * 0 and 15. |
25 | * | 25 | * SBUS interrupts are encodes as a combination of board, level and slot. |
26 | * SBUS interrupts are encoded integers including the board number | ||
27 | * (plus one), the SBUS level, and the SBUS slot number. Sun4D | ||
28 | * IRQ dispatch is done by: | ||
29 | * | ||
30 | * 1) Reading the BW local interrupt table in order to get the bus | ||
31 | * interrupt mask. | ||
32 | * | ||
33 | * This table is indexed by SBUS interrupt level which can be | ||
34 | * derived from the PIL we got interrupted on. | ||
35 | * | ||
36 | * 2) For each bus showing interrupt pending from #1, read the | ||
37 | * SBI interrupt state register. This will indicate which slots | ||
38 | * have interrupts pending for that SBUS interrupt level. | ||
39 | */ | 26 | */ |
40 | 27 | ||
28 | struct sun4d_handler_data { | ||
29 | unsigned int cpuid; /* target cpu */ | ||
30 | unsigned int real_irq; /* interrupt level */ | ||
31 | }; | ||
32 | |||
33 | |||
34 | static unsigned int sun4d_encode_irq(int board, int lvl, int slot) | ||
35 | { | ||
36 | return (board + 1) << 5 | (lvl << 2) | slot; | ||
37 | } | ||
38 | |||
41 | struct sun4d_timer_regs { | 39 | struct sun4d_timer_regs { |
42 | u32 l10_timer_limit; | 40 | u32 l10_timer_limit; |
43 | u32 l10_cur_countx; | 41 | u32 l10_cur_countx; |
@@ -48,22 +46,13 @@ struct sun4d_timer_regs { | |||
48 | 46 | ||
49 | static struct sun4d_timer_regs __iomem *sun4d_timers; | 47 | static struct sun4d_timer_regs __iomem *sun4d_timers; |
50 | 48 | ||
51 | #define TIMER_IRQ 10 | 49 | #define SUN4D_TIMER_IRQ 10 |
52 | |||
53 | #define MAX_STATIC_ALLOC 4 | ||
54 | 50 | ||
55 | /* Specify which cpu handle interrupts from which board. | 51 | /* Specify which cpu handle interrupts from which board. |
56 | * Index is board - value is cpu. | 52 | * Index is board - value is cpu. |
57 | */ | 53 | */ |
58 | static unsigned char board_to_cpu[32]; | 54 | static unsigned char board_to_cpu[32]; |
59 | 55 | ||
60 | static struct irqaction *irq_action[NR_IRQS]; | ||
61 | |||
62 | static struct sbus_action { | ||
63 | struct irqaction *action; | ||
64 | /* For SMP this needs to be extended */ | ||
65 | } *sbus_actions; | ||
66 | |||
67 | static int pil_to_sbus[] = { | 56 | static int pil_to_sbus[] = { |
68 | 0, | 57 | 0, |
69 | 0, | 58 | 0, |
@@ -83,152 +72,81 @@ static int pil_to_sbus[] = { | |||
83 | 0, | 72 | 0, |
84 | }; | 73 | }; |
85 | 74 | ||
86 | static int sbus_to_pil[] = { | ||
87 | 0, | ||
88 | 2, | ||
89 | 3, | ||
90 | 5, | ||
91 | 7, | ||
92 | 9, | ||
93 | 11, | ||
94 | 13, | ||
95 | }; | ||
96 | |||
97 | static int nsbi; | ||
98 | |||
99 | /* Exported for sun4d_smp.c */ | 75 | /* Exported for sun4d_smp.c */ |
100 | DEFINE_SPINLOCK(sun4d_imsk_lock); | 76 | DEFINE_SPINLOCK(sun4d_imsk_lock); |
101 | 77 | ||
102 | int show_sun4d_interrupts(struct seq_file *p, void *v) | 78 | /* SBUS interrupts are encoded integers including the board number |
79 | * (plus one), the SBUS level, and the SBUS slot number. Sun4D | ||
80 | * IRQ dispatch is done by: | ||
81 | * | ||
82 | * 1) Reading the BW local interrupt table in order to get the bus | ||
83 | * interrupt mask. | ||
84 | * | ||
85 | * This table is indexed by SBUS interrupt level which can be | ||
86 | * derived from the PIL we got interrupted on. | ||
87 | * | ||
88 | * 2) For each bus showing interrupt pending from #1, read the | ||
89 | * SBI interrupt state register. This will indicate which slots | ||
90 | * have interrupts pending for that SBUS interrupt level. | ||
91 | * | ||
92 | * 3) Call the genreric IRQ support. | ||
93 | */ | ||
94 | static void sun4d_sbus_handler_irq(int sbusl) | ||
103 | { | 95 | { |
104 | int i = *(loff_t *) v, j = 0, k = 0, sbusl; | 96 | unsigned int bus_mask; |
105 | struct irqaction *action; | 97 | unsigned int sbino, slot; |
106 | unsigned long flags; | 98 | unsigned int sbil; |
107 | #ifdef CONFIG_SMP | 99 | |
108 | int x; | 100 | bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff; |
109 | #endif | 101 | bw_clear_intr_mask(sbusl, bus_mask); |
110 | 102 | ||
111 | spin_lock_irqsave(&irq_action_lock, flags); | 103 | sbil = (sbusl << 2); |
112 | if (i < NR_IRQS) { | 104 | /* Loop for each pending SBI */ |
113 | sbusl = pil_to_sbus[i]; | 105 | for (sbino = 0; bus_mask; sbino++) { |
114 | if (!sbusl) { | 106 | unsigned int idx, mask; |
115 | action = *(i + irq_action); | 107 | |
116 | if (!action) | 108 | bus_mask >>= 1; |
117 | goto out_unlock; | 109 | if (!(bus_mask & 1)) |
118 | } else { | 110 | continue; |
119 | for (j = 0; j < nsbi; j++) { | 111 | /* XXX This seems to ACK the irq twice. acquire_sbi() |
120 | for (k = 0; k < 4; k++) | 112 | * XXX uses swap, therefore this writes 0xf << sbil, |
121 | action = sbus_actions[(j << 5) + (sbusl << 2) + k].action; | 113 | * XXX then later release_sbi() will write the individual |
122 | if (action) | 114 | * XXX bits which were set again. |
123 | goto found_it; | 115 | */ |
124 | } | 116 | mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil); |
125 | goto out_unlock; | 117 | mask &= (0xf << sbil); |
126 | } | 118 | |
127 | found_it: seq_printf(p, "%3d: ", i); | 119 | /* Loop for each pending SBI slot */ |
128 | #ifndef CONFIG_SMP | 120 | idx = 0; |
129 | seq_printf(p, "%10u ", kstat_irqs(i)); | 121 | slot = (1 << sbil); |
130 | #else | 122 | while (mask != 0) { |
131 | for_each_online_cpu(x) | 123 | unsigned int pil; |
132 | seq_printf(p, "%10u ", | 124 | struct irq_bucket *p; |
133 | kstat_cpu(cpu_logical_map(x)).irqs[i]); | 125 | |
134 | #endif | 126 | idx++; |
135 | seq_printf(p, "%c %s", | 127 | slot <<= 1; |
136 | (action->flags & IRQF_DISABLED) ? '+' : ' ', | 128 | if (!(mask & slot)) |
137 | action->name); | 129 | continue; |
138 | action = action->next; | 130 | |
139 | for (;;) { | 131 | mask &= ~slot; |
140 | for (; action; action = action->next) { | 132 | pil = sun4d_encode_irq(sbino, sbil, idx); |
141 | seq_printf(p, ",%s %s", | 133 | |
142 | (action->flags & IRQF_DISABLED) ? " +" : "", | 134 | p = irq_map[pil]; |
143 | action->name); | 135 | while (p) { |
144 | } | 136 | struct irq_bucket *next; |
145 | if (!sbusl) | 137 | |
146 | break; | 138 | next = p->next; |
147 | k++; | 139 | generic_handle_irq(p->irq); |
148 | if (k < 4) { | 140 | p = next; |
149 | action = sbus_actions[(j << 5) + (sbusl << 2) + k].action; | ||
150 | } else { | ||
151 | j++; | ||
152 | if (j == nsbi) | ||
153 | break; | ||
154 | k = 0; | ||
155 | action = sbus_actions[(j << 5) + (sbusl << 2)].action; | ||
156 | } | 141 | } |
142 | release_sbi(SBI2DEVID(sbino), slot); | ||
157 | } | 143 | } |
158 | seq_putc(p, '\n'); | ||
159 | } | ||
160 | out_unlock: | ||
161 | spin_unlock_irqrestore(&irq_action_lock, flags); | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | void sun4d_free_irq(unsigned int irq, void *dev_id) | ||
166 | { | ||
167 | struct irqaction *action, **actionp; | ||
168 | struct irqaction *tmp = NULL; | ||
169 | unsigned long flags; | ||
170 | |||
171 | spin_lock_irqsave(&irq_action_lock, flags); | ||
172 | if (irq < 15) | ||
173 | actionp = irq + irq_action; | ||
174 | else | ||
175 | actionp = &(sbus_actions[irq - (1 << 5)].action); | ||
176 | action = *actionp; | ||
177 | if (!action) { | ||
178 | printk(KERN_ERR "Trying to free free IRQ%d\n", irq); | ||
179 | goto out_unlock; | ||
180 | } | ||
181 | if (dev_id) { | ||
182 | for (; action; action = action->next) { | ||
183 | if (action->dev_id == dev_id) | ||
184 | break; | ||
185 | tmp = action; | ||
186 | } | ||
187 | if (!action) { | ||
188 | printk(KERN_ERR "Trying to free free shared IRQ%d\n", | ||
189 | irq); | ||
190 | goto out_unlock; | ||
191 | } | ||
192 | } else if (action->flags & IRQF_SHARED) { | ||
193 | printk(KERN_ERR "Trying to free shared IRQ%d with NULL device ID\n", | ||
194 | irq); | ||
195 | goto out_unlock; | ||
196 | } | ||
197 | if (action->flags & SA_STATIC_ALLOC) { | ||
198 | /* | ||
199 | * This interrupt is marked as specially allocated | ||
200 | * so it is a bad idea to free it. | ||
201 | */ | ||
202 | printk(KERN_ERR "Attempt to free statically allocated IRQ%d (%s)\n", | ||
203 | irq, action->name); | ||
204 | goto out_unlock; | ||
205 | } | 144 | } |
206 | |||
207 | if (tmp) | ||
208 | tmp->next = action->next; | ||
209 | else | ||
210 | *actionp = action->next; | ||
211 | |||
212 | spin_unlock_irqrestore(&irq_action_lock, flags); | ||
213 | |||
214 | synchronize_irq(irq); | ||
215 | |||
216 | spin_lock_irqsave(&irq_action_lock, flags); | ||
217 | |||
218 | kfree(action); | ||
219 | |||
220 | if (!(*actionp)) | ||
221 | __disable_irq(irq); | ||
222 | |||
223 | out_unlock: | ||
224 | spin_unlock_irqrestore(&irq_action_lock, flags); | ||
225 | } | 145 | } |
226 | 146 | ||
227 | void sun4d_handler_irq(int pil, struct pt_regs *regs) | 147 | void sun4d_handler_irq(int pil, struct pt_regs *regs) |
228 | { | 148 | { |
229 | struct pt_regs *old_regs; | 149 | struct pt_regs *old_regs; |
230 | struct irqaction *action; | ||
231 | int cpu = smp_processor_id(); | ||
232 | /* SBUS IRQ level (1 - 7) */ | 150 | /* SBUS IRQ level (1 - 7) */ |
233 | int sbusl = pil_to_sbus[pil]; | 151 | int sbusl = pil_to_sbus[pil]; |
234 | 152 | ||
@@ -239,158 +157,85 @@ void sun4d_handler_irq(int pil, struct pt_regs *regs) | |||
239 | 157 | ||
240 | old_regs = set_irq_regs(regs); | 158 | old_regs = set_irq_regs(regs); |
241 | irq_enter(); | 159 | irq_enter(); |
242 | kstat_cpu(cpu).irqs[pil]++; | 160 | if (sbusl == 0) { |
243 | if (!sbusl) { | 161 | /* cpu interrupt */ |
244 | action = *(pil + irq_action); | 162 | struct irq_bucket *p; |
245 | if (!action) | 163 | |
246 | unexpected_irq(pil, NULL, regs); | 164 | p = irq_map[pil]; |
247 | do { | 165 | while (p) { |
248 | action->handler(pil, action->dev_id); | 166 | struct irq_bucket *next; |
249 | action = action->next; | 167 | |
250 | } while (action); | 168 | next = p->next; |
169 | generic_handle_irq(p->irq); | ||
170 | p = next; | ||
171 | } | ||
251 | } else { | 172 | } else { |
252 | int bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff; | 173 | /* SBUS interrupt */ |
253 | int sbino; | 174 | sun4d_sbus_handler_irq(sbusl); |
254 | struct sbus_action *actionp; | ||
255 | unsigned mask, slot; | ||
256 | int sbil = (sbusl << 2); | ||
257 | |||
258 | bw_clear_intr_mask(sbusl, bus_mask); | ||
259 | |||
260 | /* Loop for each pending SBI */ | ||
261 | for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) | ||
262 | if (bus_mask & 1) { | ||
263 | mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil); | ||
264 | mask &= (0xf << sbil); | ||
265 | actionp = sbus_actions + (sbino << 5) + (sbil); | ||
266 | /* Loop for each pending SBI slot */ | ||
267 | for (slot = (1 << sbil); mask; slot <<= 1, actionp++) | ||
268 | if (mask & slot) { | ||
269 | mask &= ~slot; | ||
270 | action = actionp->action; | ||
271 | |||
272 | if (!action) | ||
273 | unexpected_irq(pil, NULL, regs); | ||
274 | do { | ||
275 | action->handler(pil, action->dev_id); | ||
276 | action = action->next; | ||
277 | } while (action); | ||
278 | release_sbi(SBI2DEVID(sbino), slot); | ||
279 | } | ||
280 | } | ||
281 | } | 175 | } |
282 | irq_exit(); | 176 | irq_exit(); |
283 | set_irq_regs(old_regs); | 177 | set_irq_regs(old_regs); |
284 | } | 178 | } |
285 | 179 | ||
286 | int sun4d_request_irq(unsigned int irq, | 180 | |
287 | irq_handler_t handler, | 181 | static void sun4d_mask_irq(struct irq_data *data) |
288 | unsigned long irqflags, const char *devname, void *dev_id) | ||
289 | { | 182 | { |
290 | struct irqaction *action, *tmp = NULL, **actionp; | 183 | struct sun4d_handler_data *handler_data = data->handler_data; |
184 | unsigned int real_irq; | ||
185 | #ifdef CONFIG_SMP | ||
186 | int cpuid = handler_data->cpuid; | ||
291 | unsigned long flags; | 187 | unsigned long flags; |
292 | int ret; | 188 | #endif |
293 | 189 | real_irq = handler_data->real_irq; | |
294 | if (irq > 14 && irq < (1 << 5)) { | 190 | #ifdef CONFIG_SMP |
295 | ret = -EINVAL; | 191 | spin_lock_irqsave(&sun4d_imsk_lock, flags); |
296 | goto out; | 192 | cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | (1 << real_irq)); |
297 | } | 193 | spin_unlock_irqrestore(&sun4d_imsk_lock, flags); |
298 | 194 | #else | |
299 | if (!handler) { | 195 | cc_set_imsk(cc_get_imsk() | (1 << real_irq)); |
300 | ret = -EINVAL; | 196 | #endif |
301 | goto out; | ||
302 | } | ||
303 | |||
304 | spin_lock_irqsave(&irq_action_lock, flags); | ||
305 | |||
306 | if (irq >= (1 << 5)) | ||
307 | actionp = &(sbus_actions[irq - (1 << 5)].action); | ||
308 | else | ||
309 | actionp = irq + irq_action; | ||
310 | action = *actionp; | ||
311 | |||
312 | if (action) { | ||
313 | if ((action->flags & IRQF_SHARED) && (irqflags & IRQF_SHARED)) { | ||
314 | for (tmp = action; tmp->next; tmp = tmp->next) | ||
315 | /* find last entry - tmp used below */; | ||
316 | } else { | ||
317 | ret = -EBUSY; | ||
318 | goto out_unlock; | ||
319 | } | ||
320 | if ((action->flags & IRQF_DISABLED) ^ (irqflags & IRQF_DISABLED)) { | ||
321 | printk(KERN_ERR "Attempt to mix fast and slow interrupts on IRQ%d denied\n", | ||
322 | irq); | ||
323 | ret = -EBUSY; | ||
324 | goto out_unlock; | ||
325 | } | ||
326 | action = NULL; /* Or else! */ | ||
327 | } | ||
328 | |||
329 | /* If this is flagged as statically allocated then we use our | ||
330 | * private struct which is never freed. | ||
331 | */ | ||
332 | if (irqflags & SA_STATIC_ALLOC) { | ||
333 | if (static_irq_count < MAX_STATIC_ALLOC) | ||
334 | action = &static_irqaction[static_irq_count++]; | ||
335 | else | ||
336 | printk(KERN_ERR "Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n", | ||
337 | irq, devname); | ||
338 | } | ||
339 | |||
340 | if (action == NULL) | ||
341 | action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC); | ||
342 | |||
343 | if (!action) { | ||
344 | ret = -ENOMEM; | ||
345 | goto out_unlock; | ||
346 | } | ||
347 | |||
348 | action->handler = handler; | ||
349 | action->flags = irqflags; | ||
350 | action->name = devname; | ||
351 | action->next = NULL; | ||
352 | action->dev_id = dev_id; | ||
353 | |||
354 | if (tmp) | ||
355 | tmp->next = action; | ||
356 | else | ||
357 | *actionp = action; | ||
358 | |||
359 | __enable_irq(irq); | ||
360 | |||
361 | ret = 0; | ||
362 | out_unlock: | ||
363 | spin_unlock_irqrestore(&irq_action_lock, flags); | ||
364 | out: | ||
365 | return ret; | ||
366 | } | 197 | } |
367 | 198 | ||
368 | static void sun4d_disable_irq(unsigned int irq) | 199 | static void sun4d_unmask_irq(struct irq_data *data) |
369 | { | 200 | { |
370 | int tid = board_to_cpu[(irq >> 5) - 1]; | 201 | struct sun4d_handler_data *handler_data = data->handler_data; |
202 | unsigned int real_irq; | ||
203 | #ifdef CONFIG_SMP | ||
204 | int cpuid = handler_data->cpuid; | ||
371 | unsigned long flags; | 205 | unsigned long flags; |
206 | #endif | ||
207 | real_irq = handler_data->real_irq; | ||
372 | 208 | ||
373 | if (irq < NR_IRQS) | 209 | #ifdef CONFIG_SMP |
374 | return; | ||
375 | |||
376 | spin_lock_irqsave(&sun4d_imsk_lock, flags); | 210 | spin_lock_irqsave(&sun4d_imsk_lock, flags); |
377 | cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7])); | 211 | cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | ~(1 << real_irq)); |
378 | spin_unlock_irqrestore(&sun4d_imsk_lock, flags); | 212 | spin_unlock_irqrestore(&sun4d_imsk_lock, flags); |
213 | #else | ||
214 | cc_set_imsk(cc_get_imsk() | ~(1 << real_irq)); | ||
215 | #endif | ||
379 | } | 216 | } |
380 | 217 | ||
381 | static void sun4d_enable_irq(unsigned int irq) | 218 | static unsigned int sun4d_startup_irq(struct irq_data *data) |
382 | { | 219 | { |
383 | int tid = board_to_cpu[(irq >> 5) - 1]; | 220 | irq_link(data->irq); |
384 | unsigned long flags; | 221 | sun4d_unmask_irq(data); |
385 | 222 | return 0; | |
386 | if (irq < NR_IRQS) | 223 | } |
387 | return; | ||
388 | 224 | ||
389 | spin_lock_irqsave(&sun4d_imsk_lock, flags); | 225 | static void sun4d_shutdown_irq(struct irq_data *data) |
390 | cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7])); | 226 | { |
391 | spin_unlock_irqrestore(&sun4d_imsk_lock, flags); | 227 | sun4d_mask_irq(data); |
228 | irq_unlink(data->irq); | ||
392 | } | 229 | } |
393 | 230 | ||
231 | struct irq_chip sun4d_irq = { | ||
232 | .name = "sun4d", | ||
233 | .irq_startup = sun4d_startup_irq, | ||
234 | .irq_shutdown = sun4d_shutdown_irq, | ||
235 | .irq_unmask = sun4d_unmask_irq, | ||
236 | .irq_mask = sun4d_mask_irq, | ||
237 | }; | ||
238 | |||
394 | #ifdef CONFIG_SMP | 239 | #ifdef CONFIG_SMP |
395 | static void sun4d_set_cpu_int(int cpu, int level) | 240 | static void sun4d_set_cpu_int(int cpu, int level) |
396 | { | 241 | { |
@@ -447,15 +292,16 @@ static void __init sun4d_load_profile_irqs(void) | |||
447 | unsigned int sun4d_build_device_irq(struct platform_device *op, | 292 | unsigned int sun4d_build_device_irq(struct platform_device *op, |
448 | unsigned int real_irq) | 293 | unsigned int real_irq) |
449 | { | 294 | { |
450 | static int pil_to_sbus[] = { | ||
451 | 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0, | ||
452 | }; | ||
453 | struct device_node *dp = op->dev.of_node; | 295 | struct device_node *dp = op->dev.of_node; |
454 | struct device_node *io_unit, *sbi = dp->parent; | 296 | struct device_node *io_unit, *sbi = dp->parent; |
455 | const struct linux_prom_registers *regs; | 297 | const struct linux_prom_registers *regs; |
298 | struct sun4d_handler_data *handler_data; | ||
299 | unsigned int pil; | ||
300 | unsigned int irq; | ||
456 | int board, slot; | 301 | int board, slot; |
457 | int sbusl; | 302 | int sbusl; |
458 | 303 | ||
304 | irq = 0; | ||
459 | while (sbi) { | 305 | while (sbi) { |
460 | if (!strcmp(sbi->name, "sbi")) | 306 | if (!strcmp(sbi->name, "sbi")) |
461 | break; | 307 | break; |
@@ -488,7 +334,28 @@ unsigned int sun4d_build_device_irq(struct platform_device *op, | |||
488 | 334 | ||
489 | sbusl = pil_to_sbus[real_irq]; | 335 | sbusl = pil_to_sbus[real_irq]; |
490 | if (sbusl) | 336 | if (sbusl) |
491 | return (((board + 1) << 5) + (sbusl << 2) + slot); | 337 | pil = sun4d_encode_irq(board, sbusl, slot); |
338 | else | ||
339 | pil = real_irq; | ||
340 | |||
341 | irq = irq_alloc(real_irq, pil); | ||
342 | if (irq == 0) | ||
343 | goto err_out; | ||
344 | |||
345 | handler_data = irq_get_handler_data(irq); | ||
346 | if (unlikely(handler_data)) | ||
347 | goto err_out; | ||
348 | |||
349 | handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC); | ||
350 | if (unlikely(!handler_data)) { | ||
351 | prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n"); | ||
352 | prom_halt(); | ||
353 | } | ||
354 | handler_data->cpuid = board_to_cpu[board]; | ||
355 | handler_data->real_irq = real_irq; | ||
356 | irq_set_chip_and_handler_name(irq, &sun4d_irq, | ||
357 | handle_level_irq, "level"); | ||
358 | irq_set_handler_data(irq, handler_data); | ||
492 | 359 | ||
493 | err_out: | 360 | err_out: |
494 | return real_irq; | 361 | return real_irq; |
@@ -522,6 +389,7 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn) | |||
522 | { | 389 | { |
523 | struct device_node *dp; | 390 | struct device_node *dp; |
524 | struct resource res; | 391 | struct resource res; |
392 | unsigned int irq; | ||
525 | const u32 *reg; | 393 | const u32 *reg; |
526 | int err; | 394 | int err; |
527 | 395 | ||
@@ -556,9 +424,8 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn) | |||
556 | 424 | ||
557 | master_l10_counter = &sun4d_timers->l10_cur_count; | 425 | master_l10_counter = &sun4d_timers->l10_cur_count; |
558 | 426 | ||
559 | err = request_irq(TIMER_IRQ, counter_fn, | 427 | irq = sun4d_build_device_irq(NULL, SUN4D_TIMER_IRQ); |
560 | (IRQF_DISABLED | SA_STATIC_ALLOC), | 428 | err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); |
561 | "timer", NULL); | ||
562 | if (err) { | 429 | if (err) { |
563 | prom_printf("sun4d_init_timers: request_irq() failed with %d\n", | 430 | prom_printf("sun4d_init_timers: request_irq() failed with %d\n", |
564 | err); | 431 | err); |
@@ -576,15 +443,6 @@ void __init sun4d_init_sbi_irq(void) | |||
576 | #ifdef CONFIG_SMP | 443 | #ifdef CONFIG_SMP |
577 | target_cpu = boot_cpu_id; | 444 | target_cpu = boot_cpu_id; |
578 | #endif | 445 | #endif |
579 | |||
580 | nsbi = 0; | ||
581 | for_each_node_by_name(dp, "sbi") | ||
582 | nsbi++; | ||
583 | sbus_actions = kzalloc(nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC); | ||
584 | if (!sbus_actions) { | ||
585 | prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n"); | ||
586 | prom_halt(); | ||
587 | } | ||
588 | for_each_node_by_name(dp, "sbi") { | 446 | for_each_node_by_name(dp, "sbi") { |
589 | int devid = of_getintprop_default(dp, "device-id", 0); | 447 | int devid = of_getintprop_default(dp, "device-id", 0); |
590 | int board = of_getintprop_default(dp, "board#", 0); | 448 | int board = of_getintprop_default(dp, "board#", 0); |
@@ -607,12 +465,10 @@ void __init sun4d_init_IRQ(void) | |||
607 | { | 465 | { |
608 | local_irq_disable(); | 466 | local_irq_disable(); |
609 | 467 | ||
610 | BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM); | ||
611 | BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM); | ||
612 | BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM); | 468 | BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM); |
613 | BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM); | 469 | BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM); |
614 | 470 | ||
615 | sparc_irq_config.init_timers = sun4d_init_timers; | 471 | sparc_irq_config.init_timers = sun4d_init_timers; |
616 | sparc_irq_config.build_device_irq = sun4d_build_device_irq; | 472 | sparc_irq_config.build_device_irq = sun4d_build_device_irq; |
617 | 473 | ||
618 | #ifdef CONFIG_SMP | 474 | #ifdef CONFIG_SMP |
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 69df6257a32e..422c16dad1f6 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c | |||
@@ -100,6 +100,11 @@ | |||
100 | struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS]; | 100 | struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS]; |
101 | struct sun4m_irq_global __iomem *sun4m_irq_global; | 101 | struct sun4m_irq_global __iomem *sun4m_irq_global; |
102 | 102 | ||
103 | struct sun4m_handler_data { | ||
104 | bool percpu; | ||
105 | long mask; | ||
106 | }; | ||
107 | |||
103 | /* Dave Redman (djhr@tadpole.co.uk) | 108 | /* Dave Redman (djhr@tadpole.co.uk) |
104 | * The sun4m interrupt registers. | 109 | * The sun4m interrupt registers. |
105 | */ | 110 | */ |
@@ -142,9 +147,9 @@ struct sun4m_irq_global __iomem *sun4m_irq_global; | |||
142 | #define OBP_INT_LEVEL_VME 0x40 | 147 | #define OBP_INT_LEVEL_VME 0x40 |
143 | 148 | ||
144 | #define SUN4M_TIMER_IRQ (OBP_INT_LEVEL_ONBOARD | 10) | 149 | #define SUN4M_TIMER_IRQ (OBP_INT_LEVEL_ONBOARD | 10) |
145 | #define SUM4M_PROFILE_IRQ (OBP_INT_LEVEL_ONBOARD | 14) | 150 | #define SUN4M_PROFILE_IRQ (OBP_INT_LEVEL_ONBOARD | 14) |
146 | 151 | ||
147 | static unsigned long irq_mask[0x50] = { | 152 | static unsigned long sun4m_imask[0x50] = { |
148 | /* 0x00 - SMP */ | 153 | /* 0x00 - SMP */ |
149 | 0, SUN4M_SOFT_INT(1), | 154 | 0, SUN4M_SOFT_INT(1), |
150 | SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3), | 155 | SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3), |
@@ -169,7 +174,7 @@ static unsigned long irq_mask[0x50] = { | |||
169 | SUN4M_INT_VIDEO, SUN4M_INT_MODULE, | 174 | SUN4M_INT_VIDEO, SUN4M_INT_MODULE, |
170 | SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY, | 175 | SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY, |
171 | (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), | 176 | (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), |
172 | SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR, | 177 | SUN4M_INT_AUDIO, SUN4M_INT_E14, SUN4M_INT_MODULE_ERR, |
173 | /* 0x30 - sbus */ | 178 | /* 0x30 - sbus */ |
174 | 0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1), | 179 | 0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1), |
175 | 0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3), | 180 | 0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3), |
@@ -182,105 +187,110 @@ static unsigned long irq_mask[0x50] = { | |||
182 | 0, SUN4M_INT_VME(6), 0, 0 | 187 | 0, SUN4M_INT_VME(6), 0, 0 |
183 | }; | 188 | }; |
184 | 189 | ||
185 | static unsigned long sun4m_get_irqmask(unsigned int irq) | 190 | static void sun4m_mask_irq(struct irq_data *data) |
186 | { | 191 | { |
187 | unsigned long mask; | 192 | struct sun4m_handler_data *handler_data = data->handler_data; |
188 | 193 | int cpu = smp_processor_id(); | |
189 | if (irq < 0x50) | ||
190 | mask = irq_mask[irq]; | ||
191 | else | ||
192 | mask = 0; | ||
193 | 194 | ||
194 | if (!mask) | 195 | if (handler_data->mask) { |
195 | printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n", | 196 | unsigned long flags; |
196 | irq); | ||
197 | 197 | ||
198 | return mask; | 198 | local_irq_save(flags); |
199 | if (handler_data->percpu) { | ||
200 | sbus_writel(handler_data->mask, &sun4m_irq_percpu[cpu]->set); | ||
201 | } else { | ||
202 | sbus_writel(handler_data->mask, &sun4m_irq_global->mask_set); | ||
203 | } | ||
204 | local_irq_restore(flags); | ||
205 | } | ||
199 | } | 206 | } |
200 | 207 | ||
201 | static void sun4m_disable_irq(unsigned int irq_nr) | 208 | static void sun4m_unmask_irq(struct irq_data *data) |
202 | { | 209 | { |
203 | unsigned long mask, flags; | 210 | struct sun4m_handler_data *handler_data = data->handler_data; |
204 | int cpu = smp_processor_id(); | 211 | int cpu = smp_processor_id(); |
205 | 212 | ||
206 | mask = sun4m_get_irqmask(irq_nr); | 213 | if (handler_data->mask) { |
207 | local_irq_save(flags); | 214 | unsigned long flags; |
208 | if (irq_nr > 15) | ||
209 | sbus_writel(mask, &sun4m_irq_global->mask_set); | ||
210 | else | ||
211 | sbus_writel(mask, &sun4m_irq_percpu[cpu]->set); | ||
212 | local_irq_restore(flags); | ||
213 | } | ||
214 | |||
215 | static void sun4m_enable_irq(unsigned int irq_nr) | ||
216 | { | ||
217 | unsigned long mask, flags; | ||
218 | int cpu = smp_processor_id(); | ||
219 | 215 | ||
220 | /* Dreadful floppy hack. When we use 0x2b instead of | ||
221 | * 0x0b the system blows (it starts to whistle!). | ||
222 | * So we continue to use 0x0b. Fixme ASAP. --P3 | ||
223 | */ | ||
224 | if (irq_nr != 0x0b) { | ||
225 | mask = sun4m_get_irqmask(irq_nr); | ||
226 | local_irq_save(flags); | ||
227 | if (irq_nr > 15) | ||
228 | sbus_writel(mask, &sun4m_irq_global->mask_clear); | ||
229 | else | ||
230 | sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear); | ||
231 | local_irq_restore(flags); | ||
232 | } else { | ||
233 | local_irq_save(flags); | 216 | local_irq_save(flags); |
234 | sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear); | 217 | if (handler_data->percpu) { |
218 | sbus_writel(handler_data->mask, &sun4m_irq_percpu[cpu]->clear); | ||
219 | } else { | ||
220 | sbus_writel(handler_data->mask, &sun4m_irq_global->mask_clear); | ||
221 | } | ||
235 | local_irq_restore(flags); | 222 | local_irq_restore(flags); |
236 | } | 223 | } |
237 | } | 224 | } |
238 | 225 | ||
239 | static unsigned long cpu_pil_to_imask[16] = { | 226 | static unsigned int sun4m_startup_irq(struct irq_data *data) |
240 | /*0*/ 0x00000000, | 227 | { |
241 | /*1*/ 0x00000000, | 228 | irq_link(data->irq); |
242 | /*2*/ SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0), | 229 | sun4m_unmask_irq(data); |
243 | /*3*/ SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1), | 230 | return 0; |
244 | /*4*/ SUN4M_INT_SCSI, | 231 | } |
245 | /*5*/ SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2), | ||
246 | /*6*/ SUN4M_INT_ETHERNET, | ||
247 | /*7*/ SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3), | ||
248 | /*8*/ SUN4M_INT_VIDEO, | ||
249 | /*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR, | ||
250 | /*10*/ SUN4M_INT_REALTIME, | ||
251 | /*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY, | ||
252 | /*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, | ||
253 | /*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO, | ||
254 | /*14*/ SUN4M_INT_E14, | ||
255 | /*15*/ SUN4M_INT_ERROR, | ||
256 | }; | ||
257 | 232 | ||
258 | /* We assume the caller has disabled local interrupts when these are called, | 233 | static void sun4m_shutdown_irq(struct irq_data *data) |
259 | * or else very bizarre behavior will result. | ||
260 | */ | ||
261 | static void sun4m_disable_pil_irq(unsigned int pil) | ||
262 | { | 234 | { |
263 | sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set); | 235 | sun4m_mask_irq(data); |
236 | irq_unlink(data->irq); | ||
264 | } | 237 | } |
265 | 238 | ||
266 | static void sun4m_enable_pil_irq(unsigned int pil) | 239 | static struct irq_chip sun4m_irq = { |
240 | .name = "sun4m", | ||
241 | .irq_startup = sun4m_startup_irq, | ||
242 | .irq_shutdown = sun4m_shutdown_irq, | ||
243 | .irq_mask = sun4m_mask_irq, | ||
244 | .irq_unmask = sun4m_unmask_irq, | ||
245 | }; | ||
246 | |||
247 | |||
248 | static unsigned int sun4m_build_device_irq(struct platform_device *op, | ||
249 | unsigned int real_irq) | ||
267 | { | 250 | { |
268 | sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear); | 251 | struct sun4m_handler_data *handler_data; |
252 | unsigned int irq; | ||
253 | unsigned int pil; | ||
254 | |||
255 | if (real_irq >= OBP_INT_LEVEL_VME) { | ||
256 | prom_printf("Bogus sun4m IRQ %u\n", real_irq); | ||
257 | prom_halt(); | ||
258 | } | ||
259 | pil = (real_irq & 0xf); | ||
260 | irq = irq_alloc(real_irq, pil); | ||
261 | |||
262 | if (irq == 0) | ||
263 | goto out; | ||
264 | |||
265 | handler_data = irq_get_handler_data(irq); | ||
266 | if (unlikely(handler_data)) | ||
267 | goto out; | ||
268 | |||
269 | handler_data = kzalloc(sizeof(struct sun4m_handler_data), GFP_ATOMIC); | ||
270 | if (unlikely(!handler_data)) { | ||
271 | prom_printf("IRQ: kzalloc(sun4m_handler_data) failed.\n"); | ||
272 | prom_halt(); | ||
273 | } | ||
274 | |||
275 | handler_data->mask = sun4m_imask[real_irq]; | ||
276 | handler_data->percpu = real_irq < OBP_INT_LEVEL_ONBOARD; | ||
277 | irq_set_chip_and_handler_name(irq, &sun4m_irq, | ||
278 | handle_level_irq, "level"); | ||
279 | irq_set_handler_data(irq, handler_data); | ||
280 | |||
281 | out: | ||
282 | return irq; | ||
269 | } | 283 | } |
270 | 284 | ||
271 | #ifdef CONFIG_SMP | 285 | #ifdef CONFIG_SMP |
272 | static void sun4m_send_ipi(int cpu, int level) | 286 | static void sun4m_send_ipi(int cpu, int level) |
273 | { | 287 | { |
274 | unsigned long mask = sun4m_get_irqmask(level); | 288 | sbus_writel(SUN4M_SOFT_INT(level), &sun4m_irq_percpu[cpu]->set); |
275 | |||
276 | sbus_writel(mask, &sun4m_irq_percpu[cpu]->set); | ||
277 | } | 289 | } |
278 | 290 | ||
279 | static void sun4m_clear_ipi(int cpu, int level) | 291 | static void sun4m_clear_ipi(int cpu, int level) |
280 | { | 292 | { |
281 | unsigned long mask = sun4m_get_irqmask(level); | 293 | sbus_writel(SUN4M_SOFT_INT(level), &sun4m_irq_percpu[cpu]->clear); |
282 | |||
283 | sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear); | ||
284 | } | 294 | } |
285 | 295 | ||
286 | static void sun4m_set_udt(int cpu) | 296 | static void sun4m_set_udt(int cpu) |
@@ -343,7 +353,15 @@ void sun4m_nmi(struct pt_regs *regs) | |||
343 | prom_halt(); | 353 | prom_halt(); |
344 | } | 354 | } |
345 | 355 | ||
346 | /* Exported for sun4m_smp.c */ | 356 | void sun4m_unmask_profile_irq(void) |
357 | { | ||
358 | unsigned long flags; | ||
359 | |||
360 | local_irq_save(flags); | ||
361 | sbus_writel(sun4m_imask[SUN4M_PROFILE_IRQ], &sun4m_irq_global->mask_clear); | ||
362 | local_irq_restore(flags); | ||
363 | } | ||
364 | |||
347 | void sun4m_clear_profile_irq(int cpu) | 365 | void sun4m_clear_profile_irq(int cpu) |
348 | { | 366 | { |
349 | sbus_readl(&timers_percpu[cpu]->l14_limit); | 367 | sbus_readl(&timers_percpu[cpu]->l14_limit); |
@@ -358,6 +376,7 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn) | |||
358 | { | 376 | { |
359 | struct device_node *dp = of_find_node_by_name(NULL, "counter"); | 377 | struct device_node *dp = of_find_node_by_name(NULL, "counter"); |
360 | int i, err, len, num_cpu_timers; | 378 | int i, err, len, num_cpu_timers; |
379 | unsigned int irq; | ||
361 | const u32 *addr; | 380 | const u32 *addr; |
362 | 381 | ||
363 | if (!dp) { | 382 | if (!dp) { |
@@ -384,8 +403,9 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn) | |||
384 | 403 | ||
385 | master_l10_counter = &timers_global->l10_count; | 404 | master_l10_counter = &timers_global->l10_count; |
386 | 405 | ||
387 | err = request_irq(SUN4M_TIMER_IRQ, counter_fn, | 406 | irq = sun4m_build_device_irq(NULL, SUN4M_TIMER_IRQ); |
388 | (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); | 407 | |
408 | err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); | ||
389 | if (err) { | 409 | if (err) { |
390 | printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n", | 410 | printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n", |
391 | err); | 411 | err); |
@@ -452,14 +472,11 @@ void __init sun4m_init_IRQ(void) | |||
452 | if (num_cpu_iregs == 4) | 472 | if (num_cpu_iregs == 4) |
453 | sbus_writel(0, &sun4m_irq_global->interrupt_target); | 473 | sbus_writel(0, &sun4m_irq_global->interrupt_target); |
454 | 474 | ||
455 | BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); | ||
456 | BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); | ||
457 | BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM); | ||
458 | BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM); | ||
459 | BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); | 475 | BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); |
460 | BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); | 476 | BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); |
461 | 477 | ||
462 | sparc_irq_config.init_timers = sun4m_init_timers; | 478 | sparc_irq_config.init_timers = sun4m_init_timers; |
479 | sparc_irq_config.build_device_irq = sun4m_build_device_irq; | ||
463 | 480 | ||
464 | #ifdef CONFIG_SMP | 481 | #ifdef CONFIG_SMP |
465 | BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); | 482 | BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); |
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 5cc7dc51de3d..58b8d849674c 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c | |||
@@ -150,20 +150,6 @@ void __init smp4m_smp_done(void) | |||
150 | /* Ok, they are spinning and ready to go. */ | 150 | /* Ok, they are spinning and ready to go. */ |
151 | } | 151 | } |
152 | 152 | ||
153 | /* At each hardware IRQ, we get this called to forward IRQ reception | ||
154 | * to the next processor. The caller must disable the IRQ level being | ||
155 | * serviced globally so that there are no double interrupts received. | ||
156 | * | ||
157 | * XXX See sparc64 irq.c. | ||
158 | */ | ||
159 | void smp4m_irq_rotate(int cpu) | ||
160 | { | ||
161 | int next = cpu_data(cpu).next; | ||
162 | |||
163 | if (next != cpu) | ||
164 | set_irq_udt(next); | ||
165 | } | ||
166 | |||
167 | static struct smp_funcall { | 153 | static struct smp_funcall { |
168 | smpfunc_t func; | 154 | smpfunc_t func; |
169 | unsigned long arg1; | 155 | unsigned long arg1; |
@@ -277,7 +263,7 @@ static void __cpuinit smp_setup_percpu_timer(void) | |||
277 | load_profile_irq(cpu, lvl14_resolution); | 263 | load_profile_irq(cpu, lvl14_resolution); |
278 | 264 | ||
279 | if (cpu == boot_cpu_id) | 265 | if (cpu == boot_cpu_id) |
280 | enable_pil_irq(14); | 266 | sun4m_unmask_profile_irq(); |
281 | } | 267 | } |
282 | 268 | ||
283 | static void __init smp4m_blackbox_id(unsigned *addr) | 269 | static void __init smp4m_blackbox_id(unsigned *addr) |