File: /usr/src/linux/arch/ppc/kernel/open_pic.c
1 /*
2 * BK Id: SCCS/s.open_pic.c 1.28 09/08/01 15:47:42 paulus
3 */
4 /*
5 * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
6 *
7 * Copyright (C) 1997 Geert Uytterhoeven
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file COPYING in the main directory of this archive
11 * for more details.
12 */
13
14 #include <linux/config.h>
15 #include <linux/types.h>
16 #include <linux/kernel.h>
17 #include <linux/sched.h>
18 #include <linux/init.h>
19 #include <linux/irq.h>
20 #include <linux/init.h>
21 #include <asm/ptrace.h>
22 #include <asm/signal.h>
23 #include <asm/io.h>
24 #include <asm/irq.h>
25 #include <asm/prom.h>
26 #include <asm/sections.h>
27
28 #include "local_irq.h"
29 #include "open_pic.h"
30 #include "open_pic_defs.h"
31
32 void* OpenPIC_Addr;
33 static volatile struct OpenPIC *OpenPIC = NULL;
34 u_int OpenPIC_NumInitSenses __initdata = 0;
35 u_char *OpenPIC_InitSenses __initdata = NULL;
36 extern int use_of_interrupt_tree;
37
38 void find_ISUs(void);
39
40 static u_int NumProcessors;
41 static u_int NumSources;
42 #ifdef CONFIG_POWER3
43 static int NumISUs;
44 #endif
45 static int open_pic_irq_offset;
46 static volatile unsigned char* chrp_int_ack_special;
47
48 OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
49
50 /* Global Operations */
51 static void openpic_disable_8259_pass_through(void);
52 static void openpic_set_priority(u_int pri);
53 static void openpic_set_spurious(u_int vector);
54
55 #ifdef CONFIG_SMP
56 /* Interprocessor Interrupts */
57 static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
58 static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
59 #endif
60
61 /* Timer Interrupts */
62 static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
63 static void openpic_maptimer(u_int timer, u_int cpumask);
64
65 /* Interrupt Sources */
66 static void openpic_enable_irq(u_int irq);
67 static void openpic_disable_irq(u_int irq);
68 static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
69 int is_level);
70 static void openpic_mapirq(u_int irq, u_int cpumask);
71
72 /*
73 * These functions are not used but the code is kept here
74 * for completeness and future reference.
75 */
76 static void openpic_reset(void);
77 #ifdef notused
78 static void openpic_enable_8259_pass_through(void);
79 static u_int openpic_get_priority(void);
80 static u_int openpic_get_spurious(void);
81 static void openpic_set_sense(u_int irq, int sense);
82 #endif /* notused */
83
84 /*
85 * Description of the openpic for the higher-level irq code
86 */
87 static void openpic_end_irq(unsigned int irq_nr);
88 static void openpic_ack_irq(unsigned int irq_nr);
89 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
90
91 struct hw_interrupt_type open_pic = {
92 " OpenPIC ",
93 NULL,
94 NULL,
95 openpic_enable_irq,
96 openpic_disable_irq,
97 openpic_ack_irq,
98 openpic_end_irq,
99 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 " OpenPIC ",
110 NULL,
111 NULL,
112 openpic_enable_ipi,
113 openpic_disable_ipi,
114 openpic_ack_ipi,
115 openpic_end_ipi,
116 0
117 };
118 #endif /* CONFIG_SMP */
119
120 /*
121 * Accesses to the current processor's openpic registers
122 */
123 #ifdef CONFIG_SMP
124 #define THIS_CPU Processor[cpu]
125 #define DECL_THIS_CPU int cpu = smp_hw_index[smp_processor_id()]
126 #define CHECK_THIS_CPU check_arg_cpu(cpu)
127 #else
128 #define THIS_CPU Processor[0]
129 #define DECL_THIS_CPU
130 #define CHECK_THIS_CPU
131 #endif /* CONFIG_SMP */
132
133 #if 1
134 #define check_arg_ipi(ipi) \
135 if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
136 printk("open_pic.c:%d: illegal ipi %d\n", __LINE__, ipi);
137 #define check_arg_timer(timer) \
138 if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
139 printk("open_pic.c:%d: illegal timer %d\n", __LINE__, timer);
140 #define check_arg_vec(vec) \
141 if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
142 printk("open_pic.c:%d: illegal vector %d\n", __LINE__, vec);
143 #define check_arg_pri(pri) \
144 if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
145 printk("open_pic.c:%d: illegal priority %d\n", __LINE__, pri);
146 /*
147 * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
148 * data has probably been corrupted and we're going to panic or deadlock later
149 * anyway --Troy
150 */
151 extern unsigned long* _get_SP(void);
152 #define check_arg_irq(irq) \
153 if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ \
154 printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
155 print_backtrace(_get_SP()); }
156 #define check_arg_cpu(cpu) \
157 if (cpu < 0 || cpu >= NumProcessors){ \
158 printk("open_pic.c:%d: illegal cpu %d\n", __LINE__, cpu); \
159 print_backtrace(_get_SP()); }
160 #else
161 #define check_arg_ipi(ipi) do {} while (0)
162 #define check_arg_timer(timer) do {} while (0)
163 #define check_arg_vec(vec) do {} while (0)
164 #define check_arg_pri(pri) do {} while (0)
165 #define check_arg_irq(irq) do {} while (0)
166 #define check_arg_cpu(cpu) do {} while (0)
167 #endif
168
169 #ifdef CONFIG_POWER3
170 #define GET_ISU(source) ISU[(source) >> 4][(source) & 0xf]
171 #else
172 #define GET_ISU(source) ISU[0][(source)]
173 #endif
174
175 u_int openpic_read(volatile u_int *addr)
176 {
177 u_int val;
178
179 val = in_le32(addr);
180 return val;
181 }
182
183 static inline void openpic_write(volatile u_int *addr, u_int val)
184 {
185 out_le32(addr, val);
186 }
187
188 static inline u_int openpic_readfield(volatile u_int *addr, u_int mask)
189 {
190 u_int val = openpic_read(addr);
191 return val & mask;
192 }
193
194 inline void openpic_writefield(volatile u_int *addr, u_int mask,
195 u_int field)
196 {
197 u_int val = openpic_read(addr);
198 openpic_write(addr, (val & ~mask) | (field & mask));
199 }
200
201 static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
202 {
203 openpic_writefield(addr, mask, 0);
204 }
205
206 static inline void openpic_setfield(volatile u_int *addr, u_int mask)
207 {
208 openpic_writefield(addr, mask, mask);
209 }
210
211 static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
212 u_int field)
213 {
214 openpic_setfield(addr, OPENPIC_MASK);
215 while (openpic_read(addr) & OPENPIC_ACTIVITY);
216 openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
217 }
218
219 #ifdef CONFIG_SMP
220 /* yes this is right ... bug, feature, you decide! -- tgall */
221 u_int openpic_read_IPI(volatile u_int* addr)
222 {
223 u_int val = 0;
224 #ifdef CONFIG_POWER3
225 val = in_be32(addr);
226 #else
227 val = in_le32(addr);
228 #endif
229 return val;
230 }
231
232 /* because of the power3 be / le above, this is needed */
233 inline void openpic_writefield_IPI(volatile u_int* addr, u_int mask, u_int field)
234 {
235 u_int val = openpic_read_IPI(addr);
236 openpic_write(addr, (val & ~mask) | (field & mask));
237 }
238
239 static inline void openpic_clearfield_IPI(volatile u_int *addr, u_int mask)
240 {
241 openpic_writefield_IPI(addr, mask, 0);
242 }
243
244 static inline void openpic_setfield_IPI(volatile u_int *addr, u_int mask)
245 {
246 openpic_writefield_IPI(addr, mask, mask);
247 }
248
249 static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int field)
250 {
251 openpic_setfield_IPI(addr, OPENPIC_MASK);
252
253 /* wait until it's not in use */
254 /* BenH: Is this code really enough ? I would rather check the result
255 * and eventually retry ...
256 */
257 while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY);
258
259 openpic_writefield_IPI(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
260 }
261 #endif /* CONFIG_SMP */
262
263 void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
264 int programmer_switch_irq)
265 {
266 u_int t, i;
267 u_int timerfreq;
268 const char *version;
269
270 if (!OpenPIC_Addr) {
271 printk("No OpenPIC found !\n");
272 return;
273 }
274 OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
275
276 if ( ppc_md.progress ) ppc_md.progress("openpic enter",0x122);
277
278 t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
279 switch (t & OPENPIC_FEATURE_VERSION_MASK) {
280 case 1:
281 version = "1.0";
282 break;
283 case 2:
284 version = "1.2";
285 break;
286 case 3:
287 version = "1.3";
288 break;
289 default:
290 version = "?";
291 break;
292 }
293 NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
294 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
295 NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
296 OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
297 printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n",
298 version, NumProcessors, NumSources, OpenPIC);
299 timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
300 if (timerfreq)
301 printk("OpenPIC timer frequency is %d.%06d MHz\n",
302 timerfreq / 1000000, timerfreq % 1000000);
303
304 if (!main_pic)
305 return;
306
307 open_pic_irq_offset = offset;
308 chrp_int_ack_special = (volatile unsigned char*)chrp_ack;
309
310 /* Initialize timer interrupts */
311 if ( ppc_md.progress ) ppc_md.progress("openpic timer",0x3ba);
312 for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
313 /* Disabled, Priority 0 */
314 openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+offset);
315 /* No processor */
316 openpic_maptimer(i, 0);
317 }
318
319 #ifdef CONFIG_SMP
320 /* Initialize IPI interrupts */
321 if ( ppc_md.progress ) ppc_md.progress("openpic ipi",0x3bb);
322 for (i = 0; i < OPENPIC_NUM_IPI; i++) {
323 /* Disabled, Priority 10..13 */
324 openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset);
325 /* IPIs are per-CPU */
326 irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
327 irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
328 }
329 #endif
330
331 find_ISUs();
332
333 /* Initialize external interrupts */
334 if (ppc_md.progress) ppc_md.progress("openpic ext",0x3bc);
335
336 openpic_set_priority(0xf);
337
338 /* SIOint (8259 cascade) is special */
339 if (offset) {
340 openpic_initirq(0, 8, offset, 1, 1);
341 openpic_mapirq(0, 1<<0);
342 }
343
344 /* Init all external sources */
345 for (i = 1; i < NumSources; i++) {
346 int pri, sense;
347
348 /* the bootloader may have left it enabled (bad !) */
349 openpic_disable_irq(i+offset);
350
351 pri = (i == programmer_switch_irq)? 9: 8;
352 sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
353 if (sense)
354 irq_desc[i+offset].status = IRQ_LEVEL;
355
356 /* Enabled, Priority 8 or 9 */
357 openpic_initirq(i, pri, i+offset, !sense, sense);
358 /* Processor 0 */
359 openpic_mapirq(i, 1<<0);
360 }
361
362 /* Init descriptors */
363 for (i = offset; i < NumSources + offset; i++)
364 irq_desc[i].handler = &open_pic;
365
366 /* Initialize the spurious interrupt */
367 if (ppc_md.progress) ppc_md.progress("openpic spurious",0x3bd);
368 openpic_set_spurious(OPENPIC_VEC_SPURIOUS+offset);
369
370 /* Initialize the cascade */
371 if (offset) {
372 if (request_irq(offset, no_action, SA_INTERRUPT,
373 "82c59 cascade", NULL))
374 printk("Unable to get OpenPIC IRQ 0 for cascade\n");
375 }
376 openpic_set_priority(0);
377 openpic_disable_8259_pass_through();
378
379 if (ppc_md.progress) ppc_md.progress("openpic exit",0x222);
380 }
381
382 #ifdef CONFIG_POWER3
383 void openpic_setup_ISU(int isu_num, unsigned long addr)
384 {
385 if (isu_num >= OPENPIC_MAX_ISU)
386 return;
387 ISU[isu_num] = (OpenPIC_SourcePtr) ioremap(addr, 0x400);
388 if (isu_num >= NumISUs)
389 NumISUs = isu_num + 1;
390 }
391 #endif
392
393 void find_ISUs(void)
394 {
395 #ifdef CONFIG_POWER3
396 /* Use /interrupt-controller/reg and
397 * /interrupt-controller/interrupt-ranges from OF device tree
398 * the ISU array is setup in chrp_pci.c in ibm_add_bridges
399 * as a result
400 * -- tgall
401 */
402
403 /* basically each ISU is a bus, and this assumes that
404 * open_pic_isu_count interrupts per bus are possible
405 * ISU == Interrupt Source
406 */
407 NumSources = NumISUs * 0x10;
408
409 #else
410 /* for non-distributed OpenPIC implementations it's in the IDU -- Cort */
411 ISU[0] = (OpenPIC_Source *)OpenPIC->Source;
412 #endif
413 }
414
415 static void openpic_reset(void)
416 {
417 openpic_setfield(&OpenPIC->Global.Global_Configuration0,
418 OPENPIC_CONFIG_RESET);
419 while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
420 OPENPIC_CONFIG_RESET))
421 mb();
422 }
423
424 #ifdef notused
425 static void openpic_enable_8259_pass_through(void)
426 {
427 openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
428 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
429 }
430 #endif /* notused */
431
432 static void openpic_disable_8259_pass_through(void)
433 {
434 openpic_setfield(&OpenPIC->Global.Global_Configuration0,
435 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
436 }
437
438 /*
439 * Find out the current interrupt
440 */
441 u_int openpic_irq(void)
442 {
443 u_int vec;
444 DECL_THIS_CPU;
445
446 CHECK_THIS_CPU;
447 vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
448 OPENPIC_VECTOR_MASK);
449 return vec;
450 }
451
452 void openpic_eoi(void)
453 {
454 DECL_THIS_CPU;
455
456 CHECK_THIS_CPU;
457 openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
458 /* Handle PCI write posting */
459 (void)openpic_read(&OpenPIC->THIS_CPU.EOI);
460 }
461
462 #ifdef notused
463 static u_int openpic_get_priority(void)
464 {
465 DECL_THIS_CPU;
466
467 CHECK_THIS_CPU;
468 return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
469 OPENPIC_CURRENT_TASK_PRIORITY_MASK);
470 }
471 #endif /* notused */
472
473 static void openpic_set_priority(u_int pri)
474 {
475 DECL_THIS_CPU;
476
477 CHECK_THIS_CPU;
478 check_arg_pri(pri);
479 openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
480 OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
481 }
482
483 /*
484 * Get/set the spurious vector
485 */
486 #ifdef notused
487 static u_int openpic_get_spurious(void)
488 {
489 return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
490 OPENPIC_VECTOR_MASK);
491 }
492 #endif /* notused */
493
494 static void openpic_set_spurious(u_int vec)
495 {
496 check_arg_vec(vec);
497 openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
498 vec);
499 }
500
501 #ifdef CONFIG_SMP
502 /*
503 * Convert a cpu mask from logical to physical cpu numbers.
504 */
505 static inline u32 physmask(u32 cpumask)
506 {
507 int i;
508 u32 mask = 0;
509
510 for (i = 0; i < smp_num_cpus; ++i, cpumask >>= 1)
511 mask |= (cpumask & 1) << smp_hw_index[i];
512 return mask;
513 }
514 #else
515 #define physmask(cpumask) (cpumask)
516 #endif
517
518 void openpic_init_processor(u_int cpumask)
519 {
520 openpic_write(&OpenPIC->Global.Processor_Initialization,
521 physmask(cpumask));
522 }
523
524 static spinlock_t openpic_setup_lock = SPIN_LOCK_UNLOCKED;
525
526 #ifdef CONFIG_SMP
527 /*
528 * Initialize an interprocessor interrupt (and disable it)
529 *
530 * ipi: OpenPIC interprocessor interrupt number
531 * pri: interrupt source priority
532 * vec: the vector it will produce
533 */
534 static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec)
535 {
536 check_arg_ipi(ipi);
537 check_arg_pri(pri);
538 check_arg_vec(vec);
539 openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi),
540 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
541 (pri << OPENPIC_PRIORITY_SHIFT) | vec);
542 }
543
544 /*
545 * Send an IPI to one or more CPUs
546 *
547 * Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
548 * and not a system-wide interrupt number
549 */
550 void openpic_cause_IPI(u_int ipi, u_int cpumask)
551 {
552 DECL_THIS_CPU;
553
554 CHECK_THIS_CPU;
555 check_arg_ipi(ipi);
556 openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
557 physmask(cpumask));
558 }
559
560 void openpic_request_IPIs(void)
561 {
562 int i;
563
564 /*
565 * Make sure this matches what is defined in smp.c for
566 * smp_message_{pass|recv}() or what shows up in
567 * /proc/interrupts will be wrong!!! --Troy */
568
569 if (OpenPIC == NULL)
570 return;
571
572 request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset,
573 openpic_ipi_action, 0, "IPI0 (call function)", 0);
574 request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+1,
575 openpic_ipi_action, 0, "IPI1 (reschedule)", 0);
576 request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+2,
577 openpic_ipi_action, 0, "IPI2 (invalidate tlb)", 0);
578 request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+3,
579 openpic_ipi_action, 0, "IPI3 (xmon break)", 0);
580
581 for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
582 openpic_enable_ipi(OPENPIC_VEC_IPI+open_pic_irq_offset+i);
583 }
584
585 /*
586 * Do per-cpu setup for SMP systems.
587 *
588 * Get IPI's working and start taking interrupts.
589 * -- Cort
590 */
591
592 void __init do_openpic_setup_cpu(void)
593 {
594 int i;
595 u32 msk = 1 << smp_hw_index[smp_processor_id()];
596
597 spin_lock(&openpic_setup_lock);
598
599 #ifdef CONFIG_IRQ_ALL_CPUS
600 /* let the openpic know we want intrs. default affinity
601 * is 0xffffffff until changed via /proc
602 * That's how it's done on x86. If we want it differently, then
603 * we should make sure we also change the default values of irq_affinity
604 * in irq.c.
605 */
606 for (i = 0; i < NumSources ; i++)
607 openpic_mapirq(i, openpic_read(&GET_ISU(i).Destination) | msk);
608 #endif /* CONFIG_IRQ_ALL_CPUS */
609 openpic_set_priority(0);
610
611 spin_unlock(&openpic_setup_lock);
612 }
613 #endif /* CONFIG_SMP */
614
615 /*
616 * Initialize a timer interrupt (and disable it)
617 *
618 * timer: OpenPIC timer number
619 * pri: interrupt source priority
620 * vec: the vector it will produce
621 */
622 static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec)
623 {
624 check_arg_timer(timer);
625 check_arg_pri(pri);
626 check_arg_vec(vec);
627 openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
628 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
629 (pri << OPENPIC_PRIORITY_SHIFT) | vec);
630 }
631
632 /*
633 * Map a timer interrupt to one or more CPUs
634 */
635 static void __init openpic_maptimer(u_int timer, u_int cpumask)
636 {
637 check_arg_timer(timer);
638 openpic_write(&OpenPIC->Global.Timer[timer].Destination,
639 physmask(cpumask));
640 }
641
642
643 /*
644 *
645 * All functions below take an offset'ed irq argument
646 *
647 */
648
649
650 /*
651 * Enable/disable an external interrupt source
652 *
653 * Externally called, irq is an offseted system-wide interrupt number
654 */
655 static void openpic_enable_irq(u_int irq)
656 {
657 check_arg_irq(irq);
658 openpic_clearfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
659 /* make sure mask gets to controller before we return to user */
660 do {
661 mb(); /* sync is probably useless here */
662 } while(openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
663 OPENPIC_MASK));
664 }
665
666 static void openpic_disable_irq(u_int irq)
667 {
668 u32 vp;
669
670 check_arg_irq(irq);
671 openpic_setfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
672 /* make sure mask gets to controller before we return to user */
673 do {
674 mb(); /* sync is probably useless here */
675 vp = openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
676 OPENPIC_MASK | OPENPIC_ACTIVITY);
677 } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
678 }
679
680 #ifdef CONFIG_SMP
681 /*
682 * Enable/disable an IPI interrupt source
683 *
684 * Externally called, irq is an offseted system-wide interrupt number
685 */
686 void openpic_enable_ipi(u_int irq)
687 {
688 irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
689 check_arg_ipi(irq);
690 openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
691
692 }
693
694 void openpic_disable_ipi(u_int irq)
695 {
696 irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
697 check_arg_ipi(irq);
698 openpic_setfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
699 }
700 #endif
701
702 /*
703 * Initialize an interrupt source (and disable it!)
704 *
705 * irq: OpenPIC interrupt number
706 * pri: interrupt source priority
707 * vec: the vector it will produce
708 * pol: polarity (1 for positive, 0 for negative)
709 * sense: 1 for level, 0 for edge
710 */
711 static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
712 {
713 openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
714 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
715 OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
716 (pri << OPENPIC_PRIORITY_SHIFT) | vec |
717 (pol ? OPENPIC_POLARITY_POSITIVE :
718 OPENPIC_POLARITY_NEGATIVE) |
719 (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
720 }
721
722 /*
723 * Map an interrupt source to one or more CPUs
724 */
725 static void openpic_mapirq(u_int irq, u_int physmask)
726 {
727 openpic_write(&GET_ISU(irq).Destination, physmask);
728 }
729
730 #ifdef notused
731 /*
732 * Set the sense for an interrupt source (and disable it!)
733 *
734 * sense: 1 for level, 0 for edge
735 */
736 static void openpic_set_sense(u_int irq, int sense)
737 {
738 openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
739 OPENPIC_SENSE_LEVEL,
740 (sense ? OPENPIC_SENSE_LEVEL : 0));
741 }
742 #endif /* notused */
743
744 /* No spinlocks, should not be necessary with the OpenPIC
745 * (1 register = 1 interrupt and we have the desc lock).
746 */
747 static void openpic_ack_irq(unsigned int irq_nr)
748 {
749 openpic_disable_irq(irq_nr);
750 openpic_eoi();
751 }
752
753 static void openpic_end_irq(unsigned int irq_nr)
754 {
755 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
756 openpic_enable_irq(irq_nr);
757 }
758
759 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
760 {
761 openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask));
762 }
763
764 #ifdef CONFIG_SMP
765 static void openpic_ack_ipi(unsigned int irq_nr)
766 {
767 openpic_eoi();
768 }
769
770 static void openpic_end_ipi(unsigned int irq_nr)
771 {
772 }
773
774 static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
775 {
776 smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset, regs);
777 }
778
779 #endif /* CONFIG_SMP */
780
781 /* This one may be merged with PReP and CHRP */
782 int
783 openpic_get_irq(struct pt_regs *regs)
784 {
785 /*
786 * Clean up needed. -VAL
787 */
788 #ifndef CONFIG_GEMINI
789 extern int i8259_irq(int cpu);
790 #endif
791 int irq = openpic_irq();
792
793 /* Management of the cascade should be moved out of here */
794
795 /* Yep - because openpic !=> i8259, for one thing. -VAL */
796 if (open_pic_irq_offset && irq == open_pic_irq_offset)
797 {
798 /*
799 * This magic address generates a PCI IACK cycle.
800 */
801 if ( chrp_int_ack_special )
802 irq = *chrp_int_ack_special;
803 #ifndef CONFIG_GEMINI
804 else
805 irq = i8259_irq( smp_processor_id() );
806 #endif
807 openpic_eoi();
808 }
809 if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
810 irq = -1;
811 return irq;
812 }
813
814 #ifdef CONFIG_SMP
815 void
816 smp_openpic_message_pass(int target, int msg, unsigned long data, int wait)
817 {
818 /* make sure we're sending something that translates to an IPI */
819 if (msg > 0x3) {
820 printk("SMP %d: smp_message_pass: unknown msg %d\n",
821 smp_processor_id(), msg);
822 return;
823 }
824 switch (target) {
825 case MSG_ALL:
826 openpic_cause_IPI(msg, 0xffffffff);
827 break;
828 case MSG_ALL_BUT_SELF:
829 openpic_cause_IPI(msg,
830 0xffffffff & ~(1 << smp_processor_id()));
831 break;
832 default:
833 openpic_cause_IPI(msg, 1<<target);
834 break;
835 }
836 }
837 #endif /* CONFIG_SMP */
838
839 #ifdef CONFIG_PMAC_PBOOK
840 static u32 save_ipi_vp[OPENPIC_NUM_IPI];
841 static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES];
842 static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES];
843 static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS];
844
845 void __pmac
846 openpic_sleep_save_intrs(void)
847 {
848 int i;
849 unsigned long flags;
850
851 spin_lock_irqsave(&openpic_setup_lock, flags);
852
853 for (i=0; i<NumProcessors; i++) {
854 save_cpu_task_pri[i] = openpic_read(&OpenPIC->Processor[i].Current_Task_Priority);
855 openpic_writefield(&OpenPIC->Processor[i].Current_Task_Priority,
856 OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf);
857 }
858
859 for (i=0; i<OPENPIC_NUM_IPI; i++)
860 save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i));
861 for (i=0; i<NumSources; i++) {
862 save_irq_src_vp[i] = openpic_read(&OpenPIC->Source[i].Vector_Priority)
863 & ~OPENPIC_ACTIVITY;
864 save_irq_src_dest[i] = openpic_read(&OpenPIC->Source[i].Destination);
865 }
866 spin_unlock_irqrestore(&openpic_setup_lock, flags);
867 }
868
869 void __pmac
870 openpic_sleep_restore_intrs(void)
871 {
872 int i;
873 unsigned long flags;
874
875 spin_lock_irqsave(&openpic_setup_lock, flags);
876
877 openpic_reset();
878
879 for (i=0; i<OPENPIC_NUM_IPI; i++)
880 openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i), save_ipi_vp[i]);
881 for (i=0; i<NumSources; i++) {
882 openpic_write(&OpenPIC->Source[i].Vector_Priority, save_irq_src_vp[i]);
883 openpic_write(&OpenPIC->Source[i].Destination, save_irq_src_dest[i]);
884 }
885 openpic_set_spurious(OPENPIC_VEC_SPURIOUS+open_pic_irq_offset);
886 openpic_disable_8259_pass_through();
887 for (i=0; i<NumProcessors; i++)
888 openpic_write(&OpenPIC->Processor[i].Current_Task_Priority, save_cpu_task_pri[i]);
889
890 spin_unlock_irqrestore(&openpic_setup_lock, flags);
891 }
892 #endif /* CONFIG_PMAC_PBOOK */
893