2 * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
4 * Copyright (C) 1997 Geert Uytterhoeven
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
11 #include <linux/config.h>
12 #include <linux/types.h>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/irq.h>
16 #include <linux/smp.h>
17 #include <linux/interrupt.h>
18 #include <asm/ptrace.h>
19 #include <asm/signal.h>
21 #include <asm/pgtable.h>
25 #include <asm/machdep.h>
28 #include "open_pic_defs.h"
30 #include <asm/ppcdebug.h>
33 static volatile struct OpenPIC
*OpenPIC
= NULL
;
34 u_int OpenPIC_NumInitSenses __initdata
= 0;
35 u_char
*OpenPIC_InitSenses __initdata
= NULL
;
38 * Local (static) OpenPIC Operations
42 /* Global Operations */
43 static void openpic_reset(void);
44 static void openpic_enable_8259_pass_through(void);
45 static void openpic_disable_8259_pass_through(void);
46 static u_int
openpic_irq(void);
47 static void openpic_eoi(void);
48 static u_int
openpic_get_priority(void);
49 static void openpic_set_priority(u_int pri
);
50 static u_int
openpic_get_spurious(void);
51 static void openpic_set_spurious(u_int vector
);
54 /* Interprocessor Interrupts */
55 static void openpic_initipi(u_int ipi
, u_int pri
, u_int vector
);
56 static irqreturn_t
openpic_ipi_action(int cpl
, void *dev_id
,
57 struct pt_regs
*regs
);
60 /* Timer Interrupts */
61 static void openpic_inittimer(u_int timer
, u_int pri
, u_int vector
);
62 static void openpic_maptimer(u_int timer
, u_int cpumask
);
64 /* Interrupt Sources */
65 static void openpic_enable_irq(u_int irq
);
66 static void openpic_disable_irq(u_int irq
);
67 static void openpic_initirq(u_int irq
, u_int pri
, u_int vector
, int polarity
,
69 static void openpic_mapirq(u_int irq
, u_int cpumask
);
71 static void find_ISUs(void);
73 static u_int NumProcessors
;
74 static u_int NumSources
;
76 static int open_pic_irq_offset
;
77 static volatile unsigned char* chrp_int_ack_special
;
79 OpenPIC_SourcePtr ISU
[OPENPIC_MAX_ISU
];
81 static void openpic_end_irq(unsigned int irq_nr
);
82 static void openpic_set_affinity(unsigned int irq_nr
, cpumask_t cpumask
);
84 struct hw_interrupt_type open_pic
= {
96 static void openpic_end_ipi(unsigned int irq_nr
);
97 static void openpic_enable_ipi(unsigned int irq_nr
);
98 static void openpic_disable_ipi(unsigned int irq_nr
);
100 struct hw_interrupt_type open_pic_ipi
= {
110 #endif /* CONFIG_SMP */
112 unsigned int openpic_vec_ipi
;
113 unsigned int openpic_vec_timer
;
114 unsigned int openpic_vec_spurious
;
117 * Accesses to the current processor's openpic registers
120 #define THIS_CPU Processor[cpu]
121 #define DECL_THIS_CPU int cpu = hard_smp_processor_id()
122 #define CHECK_THIS_CPU check_arg_cpu(cpu)
124 #define THIS_CPU Processor[hard_smp_processor_id()]
125 #define DECL_THIS_CPU
126 #define CHECK_THIS_CPU
127 #endif /* CONFIG_SMP */
130 #define check_arg_ipi(ipi) \
131 if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
132 printk(KERN_ERR "open_pic.c:%d: invalid ipi %d\n", __LINE__, ipi);
133 #define check_arg_timer(timer) \
134 if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
135 printk(KERN_ERR "open_pic.c:%d: invalid timer %d\n", __LINE__, timer);
136 #define check_arg_vec(vec) \
137 if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
138 printk(KERN_ERR "open_pic.c:%d: invalid vector %d\n", __LINE__, vec);
139 #define check_arg_pri(pri) \
140 if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
141 printk(KERN_ERR "open_pic.c:%d: invalid priority %d\n", __LINE__, pri);
143 * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
144 * data has probably been corrupted and we're going to panic or deadlock later
147 #define check_arg_irq(irq) \
148 if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ \
149 printk(KERN_ERR "open_pic.c:%d: invalid irq %d\n", __LINE__, irq); \
151 #define check_arg_cpu(cpu) \
152 if (cpu < 0 || cpu >= OPENPIC_MAX_PROCESSORS){ \
153 printk(KERN_ERR "open_pic.c:%d: invalid cpu %d\n", __LINE__, cpu); \
156 #define check_arg_ipi(ipi) do {} while (0)
157 #define check_arg_timer(timer) do {} while (0)
158 #define check_arg_vec(vec) do {} while (0)
159 #define check_arg_pri(pri) do {} while (0)
160 #define check_arg_irq(irq) do {} while (0)
161 #define check_arg_cpu(cpu) do {} while (0)
164 #define GET_ISU(source) ISU[(source) >> 4][(source) & 0xf]
166 void __init
pSeries_init_openpic(void)
168 struct device_node
*np
;
171 unsigned char* chrp_int_ack_special
= NULL
;
172 unsigned char init_senses
[NR_IRQS
- NUM_ISA_INTERRUPTS
];
174 #if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
175 struct device_node
*kbd
;
178 if (!(np
= of_find_node_by_name(NULL
, "pci"))
179 || !(addrp
= (unsigned int *)
180 get_property(np
, "8259-interrupt-acknowledge", NULL
)))
181 printk(KERN_ERR
"Cannot find pci to get ack address\n");
183 chrp_int_ack_special
= (unsigned char *)
184 __ioremap(addrp
[prom_n_addr_cells(np
)-1], 1, _PAGE_NO_CACHE
);
185 /* hydra still sets OpenPIC_InitSenses to a static set of values */
186 if (OpenPIC_InitSenses
== NULL
) {
187 prom_get_irq_senses(init_senses
, NUM_ISA_INTERRUPTS
, NR_IRQS
);
188 OpenPIC_InitSenses
= init_senses
;
189 OpenPIC_NumInitSenses
= NR_IRQS
- NUM_ISA_INTERRUPTS
;
191 openpic_init(1, NUM_ISA_INTERRUPTS
, chrp_int_ack_special
, nmi_irq
);
192 for (i
= 0; i
< NUM_ISA_INTERRUPTS
; i
++)
193 irq_desc
[i
].handler
= &i8259_pic
;
197 static inline u_int
openpic_read(volatile u_int
*addr
)
205 static inline void openpic_write(volatile u_int
*addr
, u_int val
)
210 static inline u_int
openpic_readfield(volatile u_int
*addr
, u_int mask
)
212 u_int val
= openpic_read(addr
);
216 static inline void openpic_writefield(volatile u_int
*addr
, u_int mask
,
219 u_int val
= openpic_read(addr
);
220 openpic_write(addr
, (val
& ~mask
) | (field
& mask
));
223 static inline void openpic_clearfield(volatile u_int
*addr
, u_int mask
)
225 openpic_writefield(addr
, mask
, 0);
228 static inline void openpic_setfield(volatile u_int
*addr
, u_int mask
)
230 openpic_writefield(addr
, mask
, mask
);
233 static void openpic_safe_writefield(volatile u_int
*addr
, u_int mask
,
236 unsigned int loops
= 100000;
238 openpic_setfield(addr
, OPENPIC_MASK
);
239 while (openpic_read(addr
) & OPENPIC_ACTIVITY
) {
241 printk(KERN_ERR
"openpic_safe_writefield timeout\n");
245 openpic_writefield(addr
, mask
| OPENPIC_MASK
, field
| OPENPIC_MASK
);
250 static int broken_ipi_registers
;
252 static u_int
openpic_read_IPI(volatile u_int
* addr
)
256 if (broken_ipi_registers
)
257 /* yes this is right ... bug, feature, you decide! -- tgall */
265 static void openpic_test_broken_IPI(void)
269 openpic_write(&OpenPIC
->Global
.IPI_Vector_Priority(0), OPENPIC_MASK
);
270 t
= openpic_read(&OpenPIC
->Global
.IPI_Vector_Priority(0));
271 if (t
== le32_to_cpu(OPENPIC_MASK
)) {
272 printk(KERN_INFO
"OpenPIC reversed IPI registers detected\n");
273 broken_ipi_registers
= 1;
277 /* because of the power3 be / le above, this is needed */
278 static inline void openpic_writefield_IPI(volatile u_int
* addr
, u_int mask
, u_int field
)
280 u_int val
= openpic_read_IPI(addr
);
281 openpic_write(addr
, (val
& ~mask
) | (field
& mask
));
284 static inline void openpic_clearfield_IPI(volatile u_int
*addr
, u_int mask
)
286 openpic_writefield_IPI(addr
, mask
, 0);
289 static inline void openpic_setfield_IPI(volatile u_int
*addr
, u_int mask
)
291 openpic_writefield_IPI(addr
, mask
, mask
);
294 static void openpic_safe_writefield_IPI(volatile u_int
*addr
, u_int mask
, u_int field
)
296 unsigned int loops
= 100000;
298 openpic_setfield_IPI(addr
, OPENPIC_MASK
);
300 /* wait until it's not in use */
301 /* BenH: Is this code really enough ? I would rather check the result
302 * and eventually retry ...
304 while(openpic_read_IPI(addr
) & OPENPIC_ACTIVITY
) {
306 printk(KERN_ERR
"openpic_safe_writefield timeout\n");
311 openpic_writefield_IPI(addr
, mask
, field
| OPENPIC_MASK
);
313 #endif /* CONFIG_SMP */
315 void __init
openpic_init(int main_pic
, int offset
, unsigned char* chrp_ack
,
316 int programmer_switch_irq
)
323 printk(KERN_INFO
"No OpenPIC found !\n");
326 OpenPIC
= (volatile struct OpenPIC
*)OpenPIC_Addr
;
328 ppc64_boot_msg(0x20, "OpenPic Init");
330 t
= openpic_read(&OpenPIC
->Global
.Feature_Reporting0
);
331 switch (t
& OPENPIC_FEATURE_VERSION_MASK
) {
345 NumProcessors
= ((t
& OPENPIC_FEATURE_LAST_PROCESSOR_MASK
) >>
346 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT
) + 1;
347 NumSources
= ((t
& OPENPIC_FEATURE_LAST_SOURCE_MASK
) >>
348 OPENPIC_FEATURE_LAST_SOURCE_SHIFT
) + 1;
349 printk(KERN_INFO
"OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n",
350 version
, NumProcessors
, NumSources
, OpenPIC
);
351 timerfreq
= openpic_read(&OpenPIC
->Global
.Timer_Frequency
);
353 printk(KERN_INFO
"OpenPIC timer frequency is %d.%06d MHz\n",
354 timerfreq
/ 1000000, timerfreq
% 1000000);
359 open_pic_irq_offset
= offset
;
360 chrp_int_ack_special
= (volatile unsigned char*)chrp_ack
;
364 /* Initialize timer interrupts */
365 for (i
= 0; i
< OPENPIC_NUM_TIMERS
; i
++) {
366 /* Disabled, Priority 0 */
367 openpic_inittimer(i
, 0, openpic_vec_timer
+i
);
369 openpic_maptimer(i
, 0);
373 /* Initialize IPI interrupts */
374 openpic_test_broken_IPI();
375 for (i
= 0; i
< OPENPIC_NUM_IPI
; i
++) {
376 /* Disabled, Priority 10..13 */
377 openpic_initipi(i
, 10+i
, openpic_vec_ipi
+i
);
378 /* IPIs are per-CPU */
379 irq_desc
[openpic_vec_ipi
+i
].status
|= IRQ_PER_CPU
;
380 irq_desc
[openpic_vec_ipi
+i
].handler
= &open_pic_ipi
;
384 /* Initialize external interrupts */
385 openpic_set_priority(0xf);
387 /* SIOint (8259 cascade) is special */
389 openpic_initirq(0, 8, offset
, 1, 1);
390 openpic_mapirq(0, 1 << get_hard_smp_processor_id(boot_cpuid
));
393 /* Init all external sources */
394 for (i
= 0; i
< NumSources
; i
++) {
397 /* skip cascade if any */
398 if (offset
&& i
== 0)
400 /* the bootloader may have left it enabled (bad !) */
401 openpic_disable_irq(i
+offset
);
403 pri
= (i
== programmer_switch_irq
)? 9: 8;
404 sense
= (i
< OpenPIC_NumInitSenses
)? OpenPIC_InitSenses
[i
]: 1;
406 irq_desc
[i
+offset
].status
= IRQ_LEVEL
;
408 /* Enabled, Priority 8 or 9 */
409 openpic_initirq(i
, pri
, i
+offset
, !sense
, sense
);
411 openpic_mapirq(i
, 1 << get_hard_smp_processor_id(boot_cpuid
));
414 /* Init descriptors */
415 for (i
= offset
; i
< NumSources
+ offset
; i
++)
416 irq_desc
[i
].handler
= &open_pic
;
418 /* Initialize the spurious interrupt */
419 openpic_set_spurious(openpic_vec_spurious
);
421 openpic_set_priority(0);
422 openpic_disable_8259_pass_through();
424 ppc64_boot_msg(0x25, "OpenPic Done");
428 * We cant do this in init_IRQ because we need the memory subsystem up for
431 static int __init
openpic_setup_i8259(void)
433 if (systemcfg
->platform
== PLATFORM_POWERMAC
)
436 if (naca
->interrupt_controller
== IC_OPEN_PIC
) {
437 /* Initialize the cascade */
438 if (request_irq(NUM_ISA_INTERRUPTS
, no_action
, SA_INTERRUPT
,
439 "82c59 cascade", NULL
))
440 printk(KERN_ERR
"Unable to get OpenPIC IRQ 0 for cascade\n");
446 arch_initcall(openpic_setup_i8259
);
448 void openpic_setup_ISU(int isu_num
, unsigned long addr
)
450 if (isu_num
>= OPENPIC_MAX_ISU
)
452 ISU
[isu_num
] = (OpenPIC_SourcePtr
) __ioremap(addr
, 0x400, _PAGE_NO_CACHE
);
453 if (isu_num
>= NumISUs
)
454 NumISUs
= isu_num
+ 1;
459 /* For PowerMac, setup ISUs on base openpic */
460 if (systemcfg
->platform
== PLATFORM_POWERMAC
) {
462 for (i
=0; i
<128; i
+=0x10) {
463 ISU
[i
>>4] = &((struct OpenPIC
*)OpenPIC_Addr
)->Source
[i
];
467 /* Use /interrupt-controller/reg and
468 * /interrupt-controller/interrupt-ranges from OF device tree
469 * the ISU array is setup in chrp_pci.c in ibm_add_bridges
474 /* basically each ISU is a bus, and this assumes that
475 * open_pic_isu_count interrupts per bus are possible
476 * ISU == Interrupt Source
478 * On G5, we keep the original NumSources provided by the controller,
479 * it's below 128, so we have room to stuff the IPIs and timers like darwin
480 * does. We put the spurrious vector up at 0xff though.
482 if (systemcfg
->platform
== PLATFORM_POWERMAC
) {
483 openpic_vec_ipi
= NumSources
;
484 openpic_vec_timer
= openpic_vec_ipi
+ 4;
485 openpic_vec_spurious
= 0xff;
487 NumSources
= NumISUs
* 0x10;
489 openpic_vec_ipi
= NumSources
+ open_pic_irq_offset
;
490 openpic_vec_timer
= openpic_vec_ipi
+ OPENPIC_NUM_IPI
;
491 openpic_vec_spurious
= openpic_vec_timer
+ OPENPIC_NUM_TIMERS
;
495 static inline void openpic_reset(void)
497 openpic_setfield(&OpenPIC
->Global
.Global_Configuration0
,
498 OPENPIC_CONFIG_RESET
);
501 static inline void openpic_enable_8259_pass_through(void)
503 openpic_clearfield(&OpenPIC
->Global
.Global_Configuration0
,
504 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE
);
507 static void openpic_disable_8259_pass_through(void)
509 openpic_setfield(&OpenPIC
->Global
.Global_Configuration0
,
510 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE
);
514 * Find out the current interrupt
516 static u_int
openpic_irq(void)
522 vec
= openpic_readfield(&OpenPIC
->THIS_CPU
.Interrupt_Acknowledge
,
523 OPENPIC_VECTOR_MASK
);
527 static void openpic_eoi(void)
532 openpic_write(&OpenPIC
->THIS_CPU
.EOI
, 0);
533 /* Handle PCI write posting */
534 (void)openpic_read(&OpenPIC
->THIS_CPU
.EOI
);
538 static inline u_int
openpic_get_priority(void)
543 return openpic_readfield(&OpenPIC
->THIS_CPU
.Current_Task_Priority
,
544 OPENPIC_CURRENT_TASK_PRIORITY_MASK
);
547 static void openpic_set_priority(u_int pri
)
553 openpic_writefield(&OpenPIC
->THIS_CPU
.Current_Task_Priority
,
554 OPENPIC_CURRENT_TASK_PRIORITY_MASK
, pri
);
558 * Get/set the spurious vector
560 static inline u_int
openpic_get_spurious(void)
562 return openpic_readfield(&OpenPIC
->Global
.Spurious_Vector
,
563 OPENPIC_VECTOR_MASK
);
566 static void openpic_set_spurious(u_int vec
)
569 openpic_writefield(&OpenPIC
->Global
.Spurious_Vector
, OPENPIC_VECTOR_MASK
,
574 * Convert a cpu mask from logical to physical cpu numbers.
576 static inline u32
physmask(u32 cpumask
)
581 for (i
= 0; i
< NR_CPUS
; ++i
, cpumask
>>= 1)
582 mask
|= (cpumask
& 1) << get_hard_smp_processor_id(i
);
586 void openpic_init_processor(u_int cpumask
)
588 openpic_write(&OpenPIC
->Global
.Processor_Initialization
,
589 physmask(cpumask
& cpus_addr(cpu_online_map
)[0]));
594 * Initialize an interprocessor interrupt (and disable it)
596 * ipi: OpenPIC interprocessor interrupt number
597 * pri: interrupt source priority
598 * vec: the vector it will produce
600 static void __init
openpic_initipi(u_int ipi
, u_int pri
, u_int vec
)
605 openpic_safe_writefield_IPI(&OpenPIC
->Global
.IPI_Vector_Priority(ipi
),
606 OPENPIC_PRIORITY_MASK
| OPENPIC_VECTOR_MASK
,
607 (pri
<< OPENPIC_PRIORITY_SHIFT
) | vec
);
611 * Send an IPI to one or more CPUs
613 * Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
614 * and not a system-wide interrupt number
616 void openpic_cause_IPI(u_int ipi
, u_int cpumask
)
622 openpic_write(&OpenPIC
->THIS_CPU
.IPI_Dispatch(ipi
),
623 physmask(cpumask
& cpus_addr(cpu_online_map
)[0]));
626 void openpic_request_IPIs(void)
631 * Make sure this matches what is defined in smp.c for
632 * smp_message_{pass|recv}() or what shows up in
633 * /proc/interrupts will be wrong!!! --Troy */
638 /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */
639 request_irq(openpic_vec_ipi
, openpic_ipi_action
, SA_INTERRUPT
,
640 "IPI0 (call function)", NULL
);
641 request_irq(openpic_vec_ipi
+1, openpic_ipi_action
, SA_INTERRUPT
,
642 "IPI1 (reschedule)", NULL
);
643 request_irq(openpic_vec_ipi
+2, openpic_ipi_action
, SA_INTERRUPT
,
644 "IPI2 (unused)", NULL
);
645 request_irq(openpic_vec_ipi
+3, openpic_ipi_action
, SA_INTERRUPT
,
646 "IPI3 (debugger break)", NULL
);
648 for ( i
= 0; i
< OPENPIC_NUM_IPI
; i
++ )
649 openpic_enable_ipi(openpic_vec_ipi
+i
);
653 * Do per-cpu setup for SMP systems.
655 * Get IPI's working and start taking interrupts.
658 static spinlock_t openpic_setup_lock __devinitdata
= SPIN_LOCK_UNLOCKED
;
660 void __devinit
do_openpic_setup_cpu(void)
662 #ifdef CONFIG_IRQ_ALL_CPUS
664 u32 msk
= 1 << hard_smp_processor_id();
667 spin_lock(&openpic_setup_lock
);
669 #ifdef CONFIG_IRQ_ALL_CPUS
670 /* let the openpic know we want intrs. default affinity
671 * is 0xffffffff until changed via /proc
672 * That's how it's done on x86. If we want it differently, then
673 * we should make sure we also change the default values of irq_affinity
676 for (i
= 0; i
< NumSources
; i
++)
677 openpic_mapirq(i
, openpic_read(&GET_ISU(i
).Destination
) | msk
);
678 #endif /* CONFIG_IRQ_ALL_CPUS */
679 openpic_set_priority(0);
681 spin_unlock(&openpic_setup_lock
);
683 #endif /* CONFIG_SMP */
686 * Initialize a timer interrupt (and disable it)
688 * timer: OpenPIC timer number
689 * pri: interrupt source priority
690 * vec: the vector it will produce
692 static void __init
openpic_inittimer(u_int timer
, u_int pri
, u_int vec
)
694 check_arg_timer(timer
);
697 openpic_safe_writefield(&OpenPIC
->Global
.Timer
[timer
].Vector_Priority
,
698 OPENPIC_PRIORITY_MASK
| OPENPIC_VECTOR_MASK
,
699 (pri
<< OPENPIC_PRIORITY_SHIFT
) | vec
);
703 * Map a timer interrupt to one or more CPUs
705 static void __init
openpic_maptimer(u_int timer
, u_int cpumask
)
707 check_arg_timer(timer
);
708 openpic_write(&OpenPIC
->Global
.Timer
[timer
].Destination
,
709 physmask(cpumask
& cpus_addr(cpu_online_map
)[0]));
715 * All functions below take an offset'ed irq argument
721 * Enable/disable an external interrupt source
723 * Externally called, irq is an offseted system-wide interrupt number
725 static void openpic_enable_irq(u_int irq
)
727 unsigned int loops
= 100000;
730 openpic_clearfield(&GET_ISU(irq
- open_pic_irq_offset
).Vector_Priority
, OPENPIC_MASK
);
731 /* make sure mask gets to controller before we return to user */
734 printk(KERN_ERR
"openpic_enable_irq timeout\n");
738 mb(); /* sync is probably useless here */
739 } while(openpic_readfield(&GET_ISU(irq
- open_pic_irq_offset
).Vector_Priority
,
743 static void openpic_disable_irq(u_int irq
)
746 unsigned int loops
= 100000;
750 openpic_setfield(&GET_ISU(irq
- open_pic_irq_offset
).Vector_Priority
, OPENPIC_MASK
);
751 /* make sure mask gets to controller before we return to user */
754 printk(KERN_ERR
"openpic_disable_irq timeout\n");
758 mb(); /* sync is probably useless here */
759 vp
= openpic_readfield(&GET_ISU(irq
- open_pic_irq_offset
).Vector_Priority
,
760 OPENPIC_MASK
| OPENPIC_ACTIVITY
);
761 } while((vp
& OPENPIC_ACTIVITY
) && !(vp
& OPENPIC_MASK
));
766 * Enable/disable an IPI interrupt source
768 * Externally called, irq is an offseted system-wide interrupt number
770 void openpic_enable_ipi(u_int irq
)
772 irq
-= openpic_vec_ipi
;
774 openpic_clearfield_IPI(&OpenPIC
->Global
.IPI_Vector_Priority(irq
), OPENPIC_MASK
);
777 void openpic_disable_ipi(u_int irq
)
779 /* NEVER disable an IPI... that's just plain wrong! */
785 * Initialize an interrupt source (and disable it!)
787 * irq: OpenPIC interrupt number
788 * pri: interrupt source priority
789 * vec: the vector it will produce
790 * pol: polarity (1 for positive, 0 for negative)
791 * sense: 1 for level, 0 for edge
793 static void openpic_initirq(u_int irq
, u_int pri
, u_int vec
, int pol
, int sense
)
795 openpic_safe_writefield(&GET_ISU(irq
).Vector_Priority
,
796 OPENPIC_PRIORITY_MASK
| OPENPIC_VECTOR_MASK
|
797 OPENPIC_SENSE_MASK
| OPENPIC_POLARITY_MASK
,
798 (pri
<< OPENPIC_PRIORITY_SHIFT
) | vec
|
799 (pol
? OPENPIC_POLARITY_POSITIVE
:
800 OPENPIC_POLARITY_NEGATIVE
) |
801 (sense
? OPENPIC_SENSE_LEVEL
: OPENPIC_SENSE_EDGE
));
805 * Map an interrupt source to one or more CPUs
807 static void openpic_mapirq(u_int irq
, u_int physmask
)
809 openpic_write(&GET_ISU(irq
).Destination
, physmask
);
813 * Set the sense for an interrupt source (and disable it!)
815 * sense: 1 for level, 0 for edge
818 static void openpic_set_sense(u_int irq
, int sense
)
820 openpic_safe_writefield(&GET_ISU(irq
).Vector_Priority
,
822 (sense
? OPENPIC_SENSE_LEVEL
: 0));
825 static int openpic_get_sense(u_int irq
)
827 return openpic_readfield(&GET_ISU(irq
).Vector_Priority
,
828 OPENPIC_SENSE_LEVEL
) != 0;
832 static void openpic_end_irq(unsigned int irq_nr
)
837 static void openpic_set_affinity(unsigned int irq_nr
, cpumask_t cpumask
)
841 cpus_and(tmp
, cpumask
, cpu_online_map
);
842 openpic_mapirq(irq_nr
- open_pic_irq_offset
, physmask(cpus_addr(tmp
)[0]));
846 static void openpic_end_ipi(unsigned int irq_nr
)
849 * IPIs are marked IRQ_PER_CPU. This has the side effect of
850 * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from
851 * applying to them. We EOI them late to avoid re-entering.
852 * We mark IPI's with SA_INTERRUPT as they must run with
858 static irqreturn_t
openpic_ipi_action(int cpl
, void *dev_id
,
859 struct pt_regs
*regs
)
861 smp_message_recv(cpl
-openpic_vec_ipi
, regs
);
865 #endif /* CONFIG_SMP */
867 int openpic_get_irq(struct pt_regs
*regs
)
869 extern int i8259_irq(int cpu
);
871 int irq
= openpic_irq();
873 if (open_pic_irq_offset
&& irq
== open_pic_irq_offset
) {
875 * This magic address generates a PCI IACK cycle.
877 if ( chrp_int_ack_special
)
878 irq
= *chrp_int_ack_special
;
880 irq
= i8259_irq( smp_processor_id() );
883 if (irq
== openpic_vec_spurious
)