diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ppc/syslib/open_pic.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/ppc/syslib/open_pic.c')
-rw-r--r-- | arch/ppc/syslib/open_pic.c | 1083 |
1 files changed, 1083 insertions, 0 deletions
diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c new file mode 100644 index 000000000000..406f36a8a681 --- /dev/null +++ b/arch/ppc/syslib/open_pic.c | |||
@@ -0,0 +1,1083 @@ | |||
1 | /* | ||
2 | * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling | ||
3 | * | ||
4 | * Copyright (C) 1997 Geert Uytterhoeven | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/sysdev.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <asm/ptrace.h> | ||
21 | #include <asm/signal.h> | ||
22 | #include <asm/io.h> | ||
23 | #include <asm/irq.h> | ||
24 | #include <asm/prom.h> | ||
25 | #include <asm/sections.h> | ||
26 | #include <asm/open_pic.h> | ||
27 | #include <asm/i8259.h> | ||
28 | |||
29 | #include "open_pic_defs.h" | ||
30 | |||
31 | #if defined(CONFIG_PRPMC800) || defined(CONFIG_85xx) | ||
32 | #define OPENPIC_BIG_ENDIAN | ||
33 | #endif | ||
34 | |||
35 | void __iomem *OpenPIC_Addr; | ||
36 | static volatile struct OpenPIC __iomem *OpenPIC = NULL; | ||
37 | |||
38 | /* | ||
39 | * We define OpenPIC_InitSenses table thusly: | ||
40 | * bit 0x1: sense, 0 for edge and 1 for level. | ||
41 | * bit 0x2: polarity, 0 for negative, 1 for positive. | ||
42 | */ | ||
43 | u_int OpenPIC_NumInitSenses __initdata = 0; | ||
44 | u_char *OpenPIC_InitSenses __initdata = NULL; | ||
45 | extern int use_of_interrupt_tree; | ||
46 | |||
47 | static u_int NumProcessors; | ||
48 | static u_int NumSources; | ||
49 | static int open_pic_irq_offset; | ||
50 | static volatile OpenPIC_Source __iomem *ISR[NR_IRQS]; | ||
51 | static int openpic_cascade_irq = -1; | ||
52 | static int (*openpic_cascade_fn)(struct pt_regs *); | ||
53 | |||
54 | /* Global Operations */ | ||
55 | static void openpic_disable_8259_pass_through(void); | ||
56 | static void openpic_set_spurious(u_int vector); | ||
57 | |||
58 | #ifdef CONFIG_SMP | ||
59 | /* Interprocessor Interrupts */ | ||
60 | static void openpic_initipi(u_int ipi, u_int pri, u_int vector); | ||
61 | static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *); | ||
62 | #endif | ||
63 | |||
64 | /* Timer Interrupts */ | ||
65 | static void openpic_inittimer(u_int timer, u_int pri, u_int vector); | ||
66 | static void openpic_maptimer(u_int timer, cpumask_t cpumask); | ||
67 | |||
68 | /* Interrupt Sources */ | ||
69 | static void openpic_enable_irq(u_int irq); | ||
70 | static void openpic_disable_irq(u_int irq); | ||
71 | static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity, | ||
72 | int is_level); | ||
73 | static void openpic_mapirq(u_int irq, cpumask_t cpumask, cpumask_t keepmask); | ||
74 | |||
75 | /* | ||
76 | * These functions are not used but the code is kept here | ||
77 | * for completeness and future reference. | ||
78 | */ | ||
79 | #ifdef notused | ||
80 | static void openpic_enable_8259_pass_through(void); | ||
81 | static u_int openpic_get_priority(void); | ||
82 | static u_int openpic_get_spurious(void); | ||
83 | static void openpic_set_sense(u_int irq, int sense); | ||
84 | #endif /* notused */ | ||
85 | |||
86 | /* | ||
87 | * Description of the openpic for the higher-level irq code | ||
88 | */ | ||
89 | static void openpic_end_irq(unsigned int irq_nr); | ||
90 | static void openpic_ack_irq(unsigned int irq_nr); | ||
91 | static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask); | ||
92 | |||
93 | struct hw_interrupt_type open_pic = { | ||
94 | .typename = " OpenPIC ", | ||
95 | .enable = openpic_enable_irq, | ||
96 | .disable = openpic_disable_irq, | ||
97 | .ack = openpic_ack_irq, | ||
98 | .end = openpic_end_irq, | ||
99 | .set_affinity = openpic_set_affinity, | ||
100 | }; | ||
101 | |||
102 | #ifdef CONFIG_SMP | ||
103 | static void openpic_end_ipi(unsigned int irq_nr); | ||
104 | static void openpic_ack_ipi(unsigned int irq_nr); | ||
105 | static void openpic_enable_ipi(unsigned int irq_nr); | ||
106 | static void openpic_disable_ipi(unsigned int irq_nr); | ||
107 | |||
108 | struct hw_interrupt_type open_pic_ipi = { | ||
109 | .typename = " OpenPIC ", | ||
110 | .enable = openpic_enable_ipi, | ||
111 | .disable = openpic_disable_ipi, | ||
112 | .ack = openpic_ack_ipi, | ||
113 | .end = openpic_end_ipi, | ||
114 | }; | ||
115 | #endif /* CONFIG_SMP */ | ||
116 | |||
117 | /* | ||
118 | * Accesses to the current processor's openpic registers | ||
119 | */ | ||
120 | #ifdef CONFIG_SMP | ||
121 | #define THIS_CPU Processor[cpu] | ||
122 | #define DECL_THIS_CPU int cpu = smp_hw_index[smp_processor_id()] | ||
123 | #define CHECK_THIS_CPU check_arg_cpu(cpu) | ||
124 | #else | ||
125 | #define THIS_CPU Processor[0] | ||
126 | #define DECL_THIS_CPU | ||
127 | #define CHECK_THIS_CPU | ||
128 | #endif /* CONFIG_SMP */ | ||
129 | |||
130 | #if 1 | ||
131 | #define check_arg_ipi(ipi) \ | ||
132 | if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \ | ||
133 | printk("open_pic.c:%d: invalid ipi %d\n", __LINE__, ipi); | ||
134 | #define check_arg_timer(timer) \ | ||
135 | if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \ | ||
136 | printk("open_pic.c:%d: invalid timer %d\n", __LINE__, timer); | ||
137 | #define check_arg_vec(vec) \ | ||
138 | if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \ | ||
139 | printk("open_pic.c:%d: invalid vector %d\n", __LINE__, vec); | ||
140 | #define check_arg_pri(pri) \ | ||
141 | if (pri < 0 || pri >= OPENPIC_NUM_PRI) \ | ||
142 | printk("open_pic.c:%d: invalid priority %d\n", __LINE__, pri); | ||
143 | /* | ||
144 | * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's | ||
145 | * data has probably been corrupted and we're going to panic or deadlock later | ||
146 | * anyway --Troy | ||
147 | */ | ||
148 | #define check_arg_irq(irq) \ | ||
149 | if (irq < open_pic_irq_offset || irq >= NumSources+open_pic_irq_offset \ | ||
150 | || ISR[irq - open_pic_irq_offset] == 0) { \ | ||
151 | printk("open_pic.c:%d: invalid irq %d\n", __LINE__, irq); \ | ||
152 | dump_stack(); } | ||
153 | #define check_arg_cpu(cpu) \ | ||
154 | if (cpu < 0 || cpu >= NumProcessors){ \ | ||
155 | printk("open_pic.c:%d: invalid cpu %d\n", __LINE__, cpu); \ | ||
156 | dump_stack(); } | ||
157 | #else | ||
158 | #define check_arg_ipi(ipi) do {} while (0) | ||
159 | #define check_arg_timer(timer) do {} while (0) | ||
160 | #define check_arg_vec(vec) do {} while (0) | ||
161 | #define check_arg_pri(pri) do {} while (0) | ||
162 | #define check_arg_irq(irq) do {} while (0) | ||
163 | #define check_arg_cpu(cpu) do {} while (0) | ||
164 | #endif | ||
165 | |||
166 | u_int openpic_read(volatile u_int __iomem *addr) | ||
167 | { | ||
168 | u_int val; | ||
169 | |||
170 | #ifdef OPENPIC_BIG_ENDIAN | ||
171 | val = in_be32(addr); | ||
172 | #else | ||
173 | val = in_le32(addr); | ||
174 | #endif | ||
175 | return val; | ||
176 | } | ||
177 | |||
178 | static inline void openpic_write(volatile u_int __iomem *addr, u_int val) | ||
179 | { | ||
180 | #ifdef OPENPIC_BIG_ENDIAN | ||
181 | out_be32(addr, val); | ||
182 | #else | ||
183 | out_le32(addr, val); | ||
184 | #endif | ||
185 | } | ||
186 | |||
187 | static inline u_int openpic_readfield(volatile u_int __iomem *addr, u_int mask) | ||
188 | { | ||
189 | u_int val = openpic_read(addr); | ||
190 | return val & mask; | ||
191 | } | ||
192 | |||
193 | inline void openpic_writefield(volatile u_int __iomem *addr, u_int mask, | ||
194 | u_int field) | ||
195 | { | ||
196 | u_int val = openpic_read(addr); | ||
197 | openpic_write(addr, (val & ~mask) | (field & mask)); | ||
198 | } | ||
199 | |||
200 | static inline void openpic_clearfield(volatile u_int __iomem *addr, u_int mask) | ||
201 | { | ||
202 | openpic_writefield(addr, mask, 0); | ||
203 | } | ||
204 | |||
205 | static inline void openpic_setfield(volatile u_int __iomem *addr, u_int mask) | ||
206 | { | ||
207 | openpic_writefield(addr, mask, mask); | ||
208 | } | ||
209 | |||
210 | static void openpic_safe_writefield(volatile u_int __iomem *addr, u_int mask, | ||
211 | u_int field) | ||
212 | { | ||
213 | openpic_setfield(addr, OPENPIC_MASK); | ||
214 | while (openpic_read(addr) & OPENPIC_ACTIVITY); | ||
215 | openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK); | ||
216 | } | ||
217 | |||
218 | #ifdef CONFIG_SMP | ||
219 | /* yes this is right ... bug, feature, you decide! -- tgall */ | ||
220 | u_int openpic_read_IPI(volatile u_int __iomem * addr) | ||
221 | { | ||
222 | u_int val = 0; | ||
223 | #if defined(OPENPIC_BIG_ENDIAN) || defined(CONFIG_POWER3) | ||
224 | val = in_be32(addr); | ||
225 | #else | ||
226 | val = in_le32(addr); | ||
227 | #endif | ||
228 | return val; | ||
229 | } | ||
230 | |||
231 | /* because of the power3 be / le above, this is needed */ | ||
232 | inline void openpic_writefield_IPI(volatile u_int __iomem * addr, u_int mask, u_int field) | ||
233 | { | ||
234 | u_int val = openpic_read_IPI(addr); | ||
235 | openpic_write(addr, (val & ~mask) | (field & mask)); | ||
236 | } | ||
237 | |||
238 | static inline void openpic_clearfield_IPI(volatile u_int __iomem *addr, u_int mask) | ||
239 | { | ||
240 | openpic_writefield_IPI(addr, mask, 0); | ||
241 | } | ||
242 | |||
243 | static inline void openpic_setfield_IPI(volatile u_int __iomem *addr, u_int mask) | ||
244 | { | ||
245 | openpic_writefield_IPI(addr, mask, mask); | ||
246 | } | ||
247 | |||
248 | static void openpic_safe_writefield_IPI(volatile u_int __iomem *addr, u_int mask, u_int field) | ||
249 | { | ||
250 | openpic_setfield_IPI(addr, OPENPIC_MASK); | ||
251 | |||
252 | /* wait until it's not in use */ | ||
253 | /* BenH: Is this code really enough ? I would rather check the result | ||
254 | * and eventually retry ... | ||
255 | */ | ||
256 | while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY); | ||
257 | |||
258 | openpic_writefield_IPI(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK); | ||
259 | } | ||
260 | #endif /* CONFIG_SMP */ | ||
261 | |||
262 | #ifdef CONFIG_EPIC_SERIAL_MODE | ||
263 | /* On platforms that may use EPIC serial mode, the default is enabled. */ | ||
264 | int epic_serial_mode = 1; | ||
265 | |||
266 | static void __init openpic_eicr_set_clk(u_int clkval) | ||
267 | { | ||
268 | openpic_writefield(&OpenPIC->Global.Global_Configuration1, | ||
269 | OPENPIC_EICR_S_CLK_MASK, (clkval << 28)); | ||
270 | } | ||
271 | |||
272 | static void __init openpic_enable_sie(void) | ||
273 | { | ||
274 | openpic_setfield(&OpenPIC->Global.Global_Configuration1, | ||
275 | OPENPIC_EICR_SIE); | ||
276 | } | ||
277 | #endif | ||
278 | |||
279 | #if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PM) | ||
280 | static void openpic_reset(void) | ||
281 | { | ||
282 | openpic_setfield(&OpenPIC->Global.Global_Configuration0, | ||
283 | OPENPIC_CONFIG_RESET); | ||
284 | while (openpic_readfield(&OpenPIC->Global.Global_Configuration0, | ||
285 | OPENPIC_CONFIG_RESET)) | ||
286 | mb(); | ||
287 | } | ||
288 | #endif | ||
289 | |||
290 | void __init openpic_set_sources(int first_irq, int num_irqs, void __iomem *first_ISR) | ||
291 | { | ||
292 | volatile OpenPIC_Source __iomem *src = first_ISR; | ||
293 | int i, last_irq; | ||
294 | |||
295 | last_irq = first_irq + num_irqs; | ||
296 | if (last_irq > NumSources) | ||
297 | NumSources = last_irq; | ||
298 | if (src == 0) | ||
299 | src = &((struct OpenPIC __iomem *)OpenPIC_Addr)->Source[first_irq]; | ||
300 | for (i = first_irq; i < last_irq; ++i, ++src) | ||
301 | ISR[i] = src; | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * The `offset' parameter defines where the interrupts handled by the | ||
306 | * OpenPIC start in the space of interrupt numbers that the kernel knows | ||
307 | * about. In other words, the OpenPIC's IRQ0 is numbered `offset' in the | ||
308 | * kernel's interrupt numbering scheme. | ||
309 | * We assume there is only one OpenPIC. | ||
310 | */ | ||
311 | void __init openpic_init(int offset) | ||
312 | { | ||
313 | u_int t, i; | ||
314 | u_int timerfreq; | ||
315 | const char *version; | ||
316 | |||
317 | if (!OpenPIC_Addr) { | ||
318 | printk("No OpenPIC found !\n"); | ||
319 | return; | ||
320 | } | ||
321 | OpenPIC = (volatile struct OpenPIC __iomem *)OpenPIC_Addr; | ||
322 | |||
323 | #ifdef CONFIG_EPIC_SERIAL_MODE | ||
324 | /* Have to start from ground zero. | ||
325 | */ | ||
326 | openpic_reset(); | ||
327 | #endif | ||
328 | |||
329 | if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122); | ||
330 | |||
331 | t = openpic_read(&OpenPIC->Global.Feature_Reporting0); | ||
332 | switch (t & OPENPIC_FEATURE_VERSION_MASK) { | ||
333 | case 1: | ||
334 | version = "1.0"; | ||
335 | break; | ||
336 | case 2: | ||
337 | version = "1.2"; | ||
338 | break; | ||
339 | case 3: | ||
340 | version = "1.3"; | ||
341 | break; | ||
342 | default: | ||
343 | version = "?"; | ||
344 | break; | ||
345 | } | ||
346 | NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> | ||
347 | OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1; | ||
348 | if (NumSources == 0) | ||
349 | openpic_set_sources(0, | ||
350 | ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> | ||
351 | OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1, | ||
352 | NULL); | ||
353 | printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", | ||
354 | version, NumProcessors, NumSources, OpenPIC); | ||
355 | timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency); | ||
356 | if (timerfreq) | ||
357 | printk("OpenPIC timer frequency is %d.%06d MHz\n", | ||
358 | timerfreq / 1000000, timerfreq % 1000000); | ||
359 | |||
360 | open_pic_irq_offset = offset; | ||
361 | |||
362 | /* Initialize timer interrupts */ | ||
363 | if ( ppc_md.progress ) ppc_md.progress("openpic: timer",0x3ba); | ||
364 | for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { | ||
365 | /* Disabled, Priority 0 */ | ||
366 | openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+offset); | ||
367 | /* No processor */ | ||
368 | openpic_maptimer(i, CPU_MASK_NONE); | ||
369 | } | ||
370 | |||
371 | #ifdef CONFIG_SMP | ||
372 | /* Initialize IPI interrupts */ | ||
373 | if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb); | ||
374 | for (i = 0; i < OPENPIC_NUM_IPI; i++) { | ||
375 | /* Disabled, Priority 10..13 */ | ||
376 | openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset); | ||
377 | /* IPIs are per-CPU */ | ||
378 | irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU; | ||
379 | irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi; | ||
380 | } | ||
381 | #endif | ||
382 | |||
383 | /* Initialize external interrupts */ | ||
384 | if (ppc_md.progress) ppc_md.progress("openpic: external",0x3bc); | ||
385 | |||
386 | openpic_set_priority(0xf); | ||
387 | |||
388 | /* Init all external sources, including possibly the cascade. */ | ||
389 | for (i = 0; i < NumSources; i++) { | ||
390 | int sense; | ||
391 | |||
392 | if (ISR[i] == 0) | ||
393 | continue; | ||
394 | |||
395 | /* the bootloader may have left it enabled (bad !) */ | ||
396 | openpic_disable_irq(i+offset); | ||
397 | |||
398 | sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: \ | ||
399 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE); | ||
400 | |||
401 | if (sense & IRQ_SENSE_MASK) | ||
402 | irq_desc[i+offset].status = IRQ_LEVEL; | ||
403 | |||
404 | /* Enabled, Priority 8 */ | ||
405 | openpic_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK), | ||
406 | (sense & IRQ_SENSE_MASK)); | ||
407 | /* Processor 0 */ | ||
408 | openpic_mapirq(i, CPU_MASK_CPU0, CPU_MASK_NONE); | ||
409 | } | ||
410 | |||
411 | /* Init descriptors */ | ||
412 | for (i = offset; i < NumSources + offset; i++) | ||
413 | irq_desc[i].handler = &open_pic; | ||
414 | |||
415 | /* Initialize the spurious interrupt */ | ||
416 | if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd); | ||
417 | openpic_set_spurious(OPENPIC_VEC_SPURIOUS); | ||
418 | openpic_disable_8259_pass_through(); | ||
419 | #ifdef CONFIG_EPIC_SERIAL_MODE | ||
420 | if (epic_serial_mode) { | ||
421 | openpic_eicr_set_clk(7); /* Slowest value until we know better */ | ||
422 | openpic_enable_sie(); | ||
423 | } | ||
424 | #endif | ||
425 | openpic_set_priority(0); | ||
426 | |||
427 | if (ppc_md.progress) ppc_md.progress("openpic: exit",0x222); | ||
428 | } | ||
429 | |||
430 | #ifdef notused | ||
431 | static void openpic_enable_8259_pass_through(void) | ||
432 | { | ||
433 | openpic_clearfield(&OpenPIC->Global.Global_Configuration0, | ||
434 | OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); | ||
435 | } | ||
436 | #endif /* notused */ | ||
437 | |||
438 | static void openpic_disable_8259_pass_through(void) | ||
439 | { | ||
440 | openpic_setfield(&OpenPIC->Global.Global_Configuration0, | ||
441 | OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); | ||
442 | } | ||
443 | |||
444 | /* | ||
445 | * Find out the current interrupt | ||
446 | */ | ||
447 | u_int openpic_irq(void) | ||
448 | { | ||
449 | u_int vec; | ||
450 | DECL_THIS_CPU; | ||
451 | |||
452 | CHECK_THIS_CPU; | ||
453 | vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge, | ||
454 | OPENPIC_VECTOR_MASK); | ||
455 | return vec; | ||
456 | } | ||
457 | |||
458 | void openpic_eoi(void) | ||
459 | { | ||
460 | DECL_THIS_CPU; | ||
461 | |||
462 | CHECK_THIS_CPU; | ||
463 | openpic_write(&OpenPIC->THIS_CPU.EOI, 0); | ||
464 | /* Handle PCI write posting */ | ||
465 | (void)openpic_read(&OpenPIC->THIS_CPU.EOI); | ||
466 | } | ||
467 | |||
468 | #ifdef notused | ||
469 | static u_int openpic_get_priority(void) | ||
470 | { | ||
471 | DECL_THIS_CPU; | ||
472 | |||
473 | CHECK_THIS_CPU; | ||
474 | return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority, | ||
475 | OPENPIC_CURRENT_TASK_PRIORITY_MASK); | ||
476 | } | ||
477 | #endif /* notused */ | ||
478 | |||
479 | void openpic_set_priority(u_int pri) | ||
480 | { | ||
481 | DECL_THIS_CPU; | ||
482 | |||
483 | CHECK_THIS_CPU; | ||
484 | check_arg_pri(pri); | ||
485 | openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority, | ||
486 | OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri); | ||
487 | } | ||
488 | |||
489 | /* | ||
490 | * Get/set the spurious vector | ||
491 | */ | ||
492 | #ifdef notused | ||
493 | static u_int openpic_get_spurious(void) | ||
494 | { | ||
495 | return openpic_readfield(&OpenPIC->Global.Spurious_Vector, | ||
496 | OPENPIC_VECTOR_MASK); | ||
497 | } | ||
498 | #endif /* notused */ | ||
499 | |||
500 | static void openpic_set_spurious(u_int vec) | ||
501 | { | ||
502 | check_arg_vec(vec); | ||
503 | openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK, | ||
504 | vec); | ||
505 | } | ||
506 | |||
507 | #ifdef CONFIG_SMP | ||
508 | /* | ||
509 | * Convert a cpu mask from logical to physical cpu numbers. | ||
510 | */ | ||
511 | static inline cpumask_t physmask(cpumask_t cpumask) | ||
512 | { | ||
513 | int i; | ||
514 | cpumask_t mask = CPU_MASK_NONE; | ||
515 | |||
516 | cpus_and(cpumask, cpu_online_map, cpumask); | ||
517 | |||
518 | for (i = 0; i < NR_CPUS; i++) | ||
519 | if (cpu_isset(i, cpumask)) | ||
520 | cpu_set(smp_hw_index[i], mask); | ||
521 | |||
522 | return mask; | ||
523 | } | ||
524 | #else | ||
525 | #define physmask(cpumask) (cpumask) | ||
526 | #endif | ||
527 | |||
528 | void openpic_reset_processor_phys(u_int mask) | ||
529 | { | ||
530 | openpic_write(&OpenPIC->Global.Processor_Initialization, mask); | ||
531 | } | ||
532 | |||
533 | #if defined(CONFIG_SMP) || defined(CONFIG_PM) | ||
534 | static DEFINE_SPINLOCK(openpic_setup_lock); | ||
535 | #endif | ||
536 | |||
537 | #ifdef CONFIG_SMP | ||
538 | /* | ||
539 | * Initialize an interprocessor interrupt (and disable it) | ||
540 | * | ||
541 | * ipi: OpenPIC interprocessor interrupt number | ||
542 | * pri: interrupt source priority | ||
543 | * vec: the vector it will produce | ||
544 | */ | ||
545 | static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec) | ||
546 | { | ||
547 | check_arg_ipi(ipi); | ||
548 | check_arg_pri(pri); | ||
549 | check_arg_vec(vec); | ||
550 | openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi), | ||
551 | OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, | ||
552 | (pri << OPENPIC_PRIORITY_SHIFT) | vec); | ||
553 | } | ||
554 | |||
555 | /* | ||
556 | * Send an IPI to one or more CPUs | ||
557 | * | ||
558 | * Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI) | ||
559 | * and not a system-wide interrupt number | ||
560 | */ | ||
561 | void openpic_cause_IPI(u_int ipi, cpumask_t cpumask) | ||
562 | { | ||
563 | cpumask_t phys; | ||
564 | DECL_THIS_CPU; | ||
565 | |||
566 | CHECK_THIS_CPU; | ||
567 | check_arg_ipi(ipi); | ||
568 | phys = physmask(cpumask); | ||
569 | openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), | ||
570 | cpus_addr(physmask(cpumask))[0]); | ||
571 | } | ||
572 | |||
573 | void openpic_request_IPIs(void) | ||
574 | { | ||
575 | int i; | ||
576 | |||
577 | /* | ||
578 | * Make sure this matches what is defined in smp.c for | ||
579 | * smp_message_{pass|recv}() or what shows up in | ||
580 | * /proc/interrupts will be wrong!!! --Troy */ | ||
581 | |||
582 | if (OpenPIC == NULL) | ||
583 | return; | ||
584 | |||
585 | /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */ | ||
586 | request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset, | ||
587 | openpic_ipi_action, SA_INTERRUPT, | ||
588 | "IPI0 (call function)", NULL); | ||
589 | request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+1, | ||
590 | openpic_ipi_action, SA_INTERRUPT, | ||
591 | "IPI1 (reschedule)", NULL); | ||
592 | request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+2, | ||
593 | openpic_ipi_action, SA_INTERRUPT, | ||
594 | "IPI2 (invalidate tlb)", NULL); | ||
595 | request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+3, | ||
596 | openpic_ipi_action, SA_INTERRUPT, | ||
597 | "IPI3 (xmon break)", NULL); | ||
598 | |||
599 | for ( i = 0; i < OPENPIC_NUM_IPI ; i++ ) | ||
600 | openpic_enable_ipi(OPENPIC_VEC_IPI+open_pic_irq_offset+i); | ||
601 | } | ||
602 | |||
603 | /* | ||
604 | * Do per-cpu setup for SMP systems. | ||
605 | * | ||
606 | * Get IPI's working and start taking interrupts. | ||
607 | * -- Cort | ||
608 | */ | ||
609 | |||
610 | void __devinit do_openpic_setup_cpu(void) | ||
611 | { | ||
612 | #ifdef CONFIG_IRQ_ALL_CPUS | ||
613 | int i; | ||
614 | cpumask_t msk = CPU_MASK_NONE; | ||
615 | #endif | ||
616 | spin_lock(&openpic_setup_lock); | ||
617 | |||
618 | #ifdef CONFIG_IRQ_ALL_CPUS | ||
619 | cpu_set(smp_hw_index[smp_processor_id()], msk); | ||
620 | |||
621 | /* let the openpic know we want intrs. default affinity | ||
622 | * is 0xffffffff until changed via /proc | ||
623 | * That's how it's done on x86. If we want it differently, then | ||
624 | * we should make sure we also change the default values of irq_affinity | ||
625 | * in irq.c. | ||
626 | */ | ||
627 | for (i = 0; i < NumSources; i++) | ||
628 | openpic_mapirq(i, msk, CPU_MASK_ALL); | ||
629 | #endif /* CONFIG_IRQ_ALL_CPUS */ | ||
630 | openpic_set_priority(0); | ||
631 | |||
632 | spin_unlock(&openpic_setup_lock); | ||
633 | } | ||
634 | #endif /* CONFIG_SMP */ | ||
635 | |||
636 | /* | ||
637 | * Initialize a timer interrupt (and disable it) | ||
638 | * | ||
639 | * timer: OpenPIC timer number | ||
640 | * pri: interrupt source priority | ||
641 | * vec: the vector it will produce | ||
642 | */ | ||
643 | static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec) | ||
644 | { | ||
645 | check_arg_timer(timer); | ||
646 | check_arg_pri(pri); | ||
647 | check_arg_vec(vec); | ||
648 | openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority, | ||
649 | OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, | ||
650 | (pri << OPENPIC_PRIORITY_SHIFT) | vec); | ||
651 | } | ||
652 | |||
653 | /* | ||
654 | * Map a timer interrupt to one or more CPUs | ||
655 | */ | ||
656 | static void __init openpic_maptimer(u_int timer, cpumask_t cpumask) | ||
657 | { | ||
658 | cpumask_t phys = physmask(cpumask); | ||
659 | check_arg_timer(timer); | ||
660 | openpic_write(&OpenPIC->Global.Timer[timer].Destination, | ||
661 | cpus_addr(phys)[0]); | ||
662 | } | ||
663 | |||
664 | /* | ||
665 | * Initalize the interrupt source which will generate an NMI. | ||
666 | * This raises the interrupt's priority from 8 to 9. | ||
667 | * | ||
668 | * irq: The logical IRQ which generates an NMI. | ||
669 | */ | ||
670 | void __init | ||
671 | openpic_init_nmi_irq(u_int irq) | ||
672 | { | ||
673 | check_arg_irq(irq); | ||
674 | openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority, | ||
675 | OPENPIC_PRIORITY_MASK, | ||
676 | 9 << OPENPIC_PRIORITY_SHIFT); | ||
677 | } | ||
678 | |||
679 | /* | ||
680 | * | ||
681 | * All functions below take an offset'ed irq argument | ||
682 | * | ||
683 | */ | ||
684 | |||
685 | /* | ||
686 | * Hookup a cascade to the OpenPIC. | ||
687 | */ | ||
688 | |||
689 | static struct irqaction openpic_cascade_irqaction = { | ||
690 | .handler = no_action, | ||
691 | .flags = SA_INTERRUPT, | ||
692 | .mask = CPU_MASK_NONE, | ||
693 | }; | ||
694 | |||
695 | void __init | ||
696 | openpic_hookup_cascade(u_int irq, char *name, | ||
697 | int (*cascade_fn)(struct pt_regs *)) | ||
698 | { | ||
699 | openpic_cascade_irq = irq; | ||
700 | openpic_cascade_fn = cascade_fn; | ||
701 | |||
702 | if (setup_irq(irq, &openpic_cascade_irqaction)) | ||
703 | printk("Unable to get OpenPIC IRQ %d for cascade\n", | ||
704 | irq - open_pic_irq_offset); | ||
705 | } | ||
706 | |||
707 | /* | ||
708 | * Enable/disable an external interrupt source | ||
709 | * | ||
710 | * Externally called, irq is an offseted system-wide interrupt number | ||
711 | */ | ||
712 | static void openpic_enable_irq(u_int irq) | ||
713 | { | ||
714 | volatile u_int __iomem *vpp; | ||
715 | |||
716 | check_arg_irq(irq); | ||
717 | vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority; | ||
718 | openpic_clearfield(vpp, OPENPIC_MASK); | ||
719 | /* make sure mask gets to controller before we return to user */ | ||
720 | do { | ||
721 | mb(); /* sync is probably useless here */ | ||
722 | } while (openpic_readfield(vpp, OPENPIC_MASK)); | ||
723 | } | ||
724 | |||
725 | static void openpic_disable_irq(u_int irq) | ||
726 | { | ||
727 | volatile u_int __iomem *vpp; | ||
728 | u32 vp; | ||
729 | |||
730 | check_arg_irq(irq); | ||
731 | vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority; | ||
732 | openpic_setfield(vpp, OPENPIC_MASK); | ||
733 | /* make sure mask gets to controller before we return to user */ | ||
734 | do { | ||
735 | mb(); /* sync is probably useless here */ | ||
736 | vp = openpic_readfield(vpp, OPENPIC_MASK | OPENPIC_ACTIVITY); | ||
737 | } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK)); | ||
738 | } | ||
739 | |||
740 | #ifdef CONFIG_SMP | ||
741 | /* | ||
742 | * Enable/disable an IPI interrupt source | ||
743 | * | ||
744 | * Externally called, irq is an offseted system-wide interrupt number | ||
745 | */ | ||
746 | void openpic_enable_ipi(u_int irq) | ||
747 | { | ||
748 | irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset); | ||
749 | check_arg_ipi(irq); | ||
750 | openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK); | ||
751 | |||
752 | } | ||
753 | |||
754 | void openpic_disable_ipi(u_int irq) | ||
755 | { | ||
756 | irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset); | ||
757 | check_arg_ipi(irq); | ||
758 | openpic_setfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK); | ||
759 | } | ||
760 | #endif | ||
761 | |||
762 | /* | ||
763 | * Initialize an interrupt source (and disable it!) | ||
764 | * | ||
765 | * irq: OpenPIC interrupt number | ||
766 | * pri: interrupt source priority | ||
767 | * vec: the vector it will produce | ||
768 | * pol: polarity (1 for positive, 0 for negative) | ||
769 | * sense: 1 for level, 0 for edge | ||
770 | */ | ||
771 | static void __init | ||
772 | openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense) | ||
773 | { | ||
774 | openpic_safe_writefield(&ISR[irq]->Vector_Priority, | ||
775 | OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | | ||
776 | OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK, | ||
777 | (pri << OPENPIC_PRIORITY_SHIFT) | vec | | ||
778 | (pol ? OPENPIC_POLARITY_POSITIVE : | ||
779 | OPENPIC_POLARITY_NEGATIVE) | | ||
780 | (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE)); | ||
781 | } | ||
782 | |||
783 | /* | ||
784 | * Map an interrupt source to one or more CPUs | ||
785 | */ | ||
786 | static void openpic_mapirq(u_int irq, cpumask_t physmask, cpumask_t keepmask) | ||
787 | { | ||
788 | if (ISR[irq] == 0) | ||
789 | return; | ||
790 | if (!cpus_empty(keepmask)) { | ||
791 | cpumask_t irqdest = { .bits[0] = openpic_read(&ISR[irq]->Destination) }; | ||
792 | cpus_and(irqdest, irqdest, keepmask); | ||
793 | cpus_or(physmask, physmask, irqdest); | ||
794 | } | ||
795 | openpic_write(&ISR[irq]->Destination, cpus_addr(physmask)[0]); | ||
796 | } | ||
797 | |||
798 | #ifdef notused | ||
799 | /* | ||
800 | * Set the sense for an interrupt source (and disable it!) | ||
801 | * | ||
802 | * sense: 1 for level, 0 for edge | ||
803 | */ | ||
804 | static void openpic_set_sense(u_int irq, int sense) | ||
805 | { | ||
806 | if (ISR[irq] != 0) | ||
807 | openpic_safe_writefield(&ISR[irq]->Vector_Priority, | ||
808 | OPENPIC_SENSE_LEVEL, | ||
809 | (sense ? OPENPIC_SENSE_LEVEL : 0)); | ||
810 | } | ||
811 | #endif /* notused */ | ||
812 | |||
813 | /* No spinlocks, should not be necessary with the OpenPIC | ||
814 | * (1 register = 1 interrupt and we have the desc lock). | ||
815 | */ | ||
816 | static void openpic_ack_irq(unsigned int irq_nr) | ||
817 | { | ||
818 | #ifdef __SLOW_VERSION__ | ||
819 | openpic_disable_irq(irq_nr); | ||
820 | openpic_eoi(); | ||
821 | #else | ||
822 | if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0) | ||
823 | openpic_eoi(); | ||
824 | #endif | ||
825 | } | ||
826 | |||
827 | static void openpic_end_irq(unsigned int irq_nr) | ||
828 | { | ||
829 | #ifdef __SLOW_VERSION__ | ||
830 | if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) | ||
831 | && irq_desc[irq_nr].action) | ||
832 | openpic_enable_irq(irq_nr); | ||
833 | #else | ||
834 | if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0) | ||
835 | openpic_eoi(); | ||
836 | #endif | ||
837 | } | ||
838 | |||
839 | static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask) | ||
840 | { | ||
841 | openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask), CPU_MASK_NONE); | ||
842 | } | ||
843 | |||
844 | #ifdef CONFIG_SMP | ||
845 | static void openpic_ack_ipi(unsigned int irq_nr) | ||
846 | { | ||
847 | openpic_eoi(); | ||
848 | } | ||
849 | |||
850 | static void openpic_end_ipi(unsigned int irq_nr) | ||
851 | { | ||
852 | } | ||
853 | |||
854 | static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) | ||
855 | { | ||
856 | smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset, regs); | ||
857 | return IRQ_HANDLED; | ||
858 | } | ||
859 | |||
860 | #endif /* CONFIG_SMP */ | ||
861 | |||
862 | int | ||
863 | openpic_get_irq(struct pt_regs *regs) | ||
864 | { | ||
865 | int irq = openpic_irq(); | ||
866 | |||
867 | /* | ||
868 | * Check for the cascade interrupt and call the cascaded | ||
869 | * interrupt controller function (usually i8259_irq) if so. | ||
870 | * This should move to irq.c eventually. -- paulus | ||
871 | */ | ||
872 | if (irq == openpic_cascade_irq && openpic_cascade_fn != NULL) { | ||
873 | int cirq = openpic_cascade_fn(regs); | ||
874 | |||
875 | /* Allow for the cascade being shared with other devices */ | ||
876 | if (cirq != -1) { | ||
877 | irq = cirq; | ||
878 | openpic_eoi(); | ||
879 | } | ||
880 | } else if (irq == OPENPIC_VEC_SPURIOUS) | ||
881 | irq = -1; | ||
882 | return irq; | ||
883 | } | ||
884 | |||
885 | #ifdef CONFIG_SMP | ||
886 | void | ||
887 | smp_openpic_message_pass(int target, int msg, unsigned long data, int wait) | ||
888 | { | ||
889 | cpumask_t mask = CPU_MASK_ALL; | ||
890 | /* make sure we're sending something that translates to an IPI */ | ||
891 | if (msg > 0x3) { | ||
892 | printk("SMP %d: smp_message_pass: unknown msg %d\n", | ||
893 | smp_processor_id(), msg); | ||
894 | return; | ||
895 | } | ||
896 | switch (target) { | ||
897 | case MSG_ALL: | ||
898 | openpic_cause_IPI(msg, mask); | ||
899 | break; | ||
900 | case MSG_ALL_BUT_SELF: | ||
901 | cpu_clear(smp_processor_id(), mask); | ||
902 | openpic_cause_IPI(msg, mask); | ||
903 | break; | ||
904 | default: | ||
905 | openpic_cause_IPI(msg, cpumask_of_cpu(target)); | ||
906 | break; | ||
907 | } | ||
908 | } | ||
909 | #endif /* CONFIG_SMP */ | ||
910 | |||
911 | #ifdef CONFIG_PM | ||
912 | |||
913 | /* | ||
914 | * We implement the IRQ controller as a sysdev and put it | ||
915 | * to sleep at powerdown stage (the callback is named suspend, | ||
916 | * but it's old semantics, for the Device Model, it's really | ||
917 | * powerdown). The possible problem is that another sysdev that | ||
918 | * happens to be suspend after this one will have interrupts off, | ||
919 | * that may be an issue... For now, this isn't an issue on pmac | ||
920 | * though... | ||
921 | */ | ||
922 | |||
923 | static u32 save_ipi_vp[OPENPIC_NUM_IPI]; | ||
924 | static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES]; | ||
925 | static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES]; | ||
926 | static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS]; | ||
927 | static int openpic_suspend_count; | ||
928 | |||
929 | static void openpic_cached_enable_irq(u_int irq) | ||
930 | { | ||
931 | check_arg_irq(irq); | ||
932 | save_irq_src_vp[irq - open_pic_irq_offset] &= ~OPENPIC_MASK; | ||
933 | } | ||
934 | |||
935 | static void openpic_cached_disable_irq(u_int irq) | ||
936 | { | ||
937 | check_arg_irq(irq); | ||
938 | save_irq_src_vp[irq - open_pic_irq_offset] |= OPENPIC_MASK; | ||
939 | } | ||
940 | |||
941 | /* WARNING: Can be called directly by the cpufreq code with NULL parameter, | ||
942 | * we need something better to deal with that... Maybe switch to S1 for | ||
943 | * cpufreq changes | ||
944 | */ | ||
945 | int openpic_suspend(struct sys_device *sysdev, u32 state) | ||
946 | { | ||
947 | int i; | ||
948 | unsigned long flags; | ||
949 | |||
950 | spin_lock_irqsave(&openpic_setup_lock, flags); | ||
951 | |||
952 | if (openpic_suspend_count++ > 0) { | ||
953 | spin_unlock_irqrestore(&openpic_setup_lock, flags); | ||
954 | return 0; | ||
955 | } | ||
956 | |||
957 | openpic_set_priority(0xf); | ||
958 | |||
959 | open_pic.enable = openpic_cached_enable_irq; | ||
960 | open_pic.disable = openpic_cached_disable_irq; | ||
961 | |||
962 | for (i=0; i<NumProcessors; i++) { | ||
963 | save_cpu_task_pri[i] = openpic_read(&OpenPIC->Processor[i].Current_Task_Priority); | ||
964 | openpic_writefield(&OpenPIC->Processor[i].Current_Task_Priority, | ||
965 | OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf); | ||
966 | } | ||
967 | |||
968 | for (i=0; i<OPENPIC_NUM_IPI; i++) | ||
969 | save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i)); | ||
970 | for (i=0; i<NumSources; i++) { | ||
971 | if (ISR[i] == 0) | ||
972 | continue; | ||
973 | save_irq_src_vp[i] = openpic_read(&ISR[i]->Vector_Priority) & ~OPENPIC_ACTIVITY; | ||
974 | save_irq_src_dest[i] = openpic_read(&ISR[i]->Destination); | ||
975 | } | ||
976 | |||
977 | spin_unlock_irqrestore(&openpic_setup_lock, flags); | ||
978 | |||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | /* WARNING: Can be called directly by the cpufreq code with NULL parameter, | ||
983 | * we need something better to deal with that... Maybe switch to S1 for | ||
984 | * cpufreq changes | ||
985 | */ | ||
986 | int openpic_resume(struct sys_device *sysdev) | ||
987 | { | ||
988 | int i; | ||
989 | unsigned long flags; | ||
990 | u32 vppmask = OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | | ||
991 | OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK | | ||
992 | OPENPIC_MASK; | ||
993 | |||
994 | spin_lock_irqsave(&openpic_setup_lock, flags); | ||
995 | |||
996 | if ((--openpic_suspend_count) > 0) { | ||
997 | spin_unlock_irqrestore(&openpic_setup_lock, flags); | ||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | openpic_reset(); | ||
1002 | |||
1003 | /* OpenPIC sometimes seem to need some time to be fully back up... */ | ||
1004 | do { | ||
1005 | openpic_set_spurious(OPENPIC_VEC_SPURIOUS); | ||
1006 | } while(openpic_readfield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK) | ||
1007 | != OPENPIC_VEC_SPURIOUS); | ||
1008 | |||
1009 | openpic_disable_8259_pass_through(); | ||
1010 | |||
1011 | for (i=0; i<OPENPIC_NUM_IPI; i++) | ||
1012 | openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i), | ||
1013 | save_ipi_vp[i]); | ||
1014 | for (i=0; i<NumSources; i++) { | ||
1015 | if (ISR[i] == 0) | ||
1016 | continue; | ||
1017 | openpic_write(&ISR[i]->Destination, save_irq_src_dest[i]); | ||
1018 | openpic_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]); | ||
1019 | /* make sure mask gets to controller before we return to user */ | ||
1020 | do { | ||
1021 | openpic_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]); | ||
1022 | } while (openpic_readfield(&ISR[i]->Vector_Priority, vppmask) | ||
1023 | != (save_irq_src_vp[i] & vppmask)); | ||
1024 | } | ||
1025 | for (i=0; i<NumProcessors; i++) | ||
1026 | openpic_write(&OpenPIC->Processor[i].Current_Task_Priority, | ||
1027 | save_cpu_task_pri[i]); | ||
1028 | |||
1029 | open_pic.enable = openpic_enable_irq; | ||
1030 | open_pic.disable = openpic_disable_irq; | ||
1031 | |||
1032 | openpic_set_priority(0); | ||
1033 | |||
1034 | spin_unlock_irqrestore(&openpic_setup_lock, flags); | ||
1035 | |||
1036 | return 0; | ||
1037 | } | ||
1038 | |||
1039 | #endif /* CONFIG_PM */ | ||
1040 | |||
1041 | static struct sysdev_class openpic_sysclass = { | ||
1042 | set_kset_name("openpic"), | ||
1043 | }; | ||
1044 | |||
1045 | static struct sys_device device_openpic = { | ||
1046 | .id = 0, | ||
1047 | .cls = &openpic_sysclass, | ||
1048 | }; | ||
1049 | |||
1050 | static struct sysdev_driver driver_openpic = { | ||
1051 | #ifdef CONFIG_PM | ||
1052 | .suspend = &openpic_suspend, | ||
1053 | .resume = &openpic_resume, | ||
1054 | #endif /* CONFIG_PM */ | ||
1055 | }; | ||
1056 | |||
1057 | static int __init init_openpic_sysfs(void) | ||
1058 | { | ||
1059 | int rc; | ||
1060 | |||
1061 | if (!OpenPIC_Addr) | ||
1062 | return -ENODEV; | ||
1063 | printk(KERN_DEBUG "Registering openpic with sysfs...\n"); | ||
1064 | rc = sysdev_class_register(&openpic_sysclass); | ||
1065 | if (rc) { | ||
1066 | printk(KERN_ERR "Failed registering openpic sys class\n"); | ||
1067 | return -ENODEV; | ||
1068 | } | ||
1069 | rc = sysdev_register(&device_openpic); | ||
1070 | if (rc) { | ||
1071 | printk(KERN_ERR "Failed registering openpic sys device\n"); | ||
1072 | return -ENODEV; | ||
1073 | } | ||
1074 | rc = sysdev_driver_register(&openpic_sysclass, &driver_openpic); | ||
1075 | if (rc) { | ||
1076 | printk(KERN_ERR "Failed registering openpic sys driver\n"); | ||
1077 | return -ENODEV; | ||
1078 | } | ||
1079 | return 0; | ||
1080 | } | ||
1081 | |||
1082 | subsys_initcall(init_openpic_sysfs); | ||
1083 | |||