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;
39 static u_int NumProcessors;
40 static u_int NumSources;
42 static int open_pic_irq_offset;
43 static volatile unsigned char* chrp_int_ack_special;
44 static int broken_ipi_registers;
46 OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
48 static void openpic_end_irq(unsigned int irq_nr);
49 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
51 struct hw_interrupt_type open_pic = {
63 static void openpic_end_ipi(unsigned int irq_nr);
64 static void openpic_enable_ipi(unsigned int irq_nr);
65 static void openpic_disable_ipi(unsigned int irq_nr);
67 struct hw_interrupt_type open_pic_ipi = {
77 #endif /* CONFIG_SMP */
79 unsigned int openpic_vec_ipi;
80 unsigned int openpic_vec_timer;
81 unsigned int openpic_vec_spurious;
84 * Accesses to the current processor's openpic registers
87 #define THIS_CPU Processor[cpu]
88 #define DECL_THIS_CPU int cpu = smp_processor_id()
89 #define CHECK_THIS_CPU check_arg_cpu(cpu)
91 #define THIS_CPU Processor[smp_processor_id()]
93 #define CHECK_THIS_CPU
94 #endif /* CONFIG_SMP */
97 #define check_arg_ipi(ipi) \
98 if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
99 printk(KERN_ERR "open_pic.c:%d: invalid ipi %d\n", __LINE__, ipi);
100 #define check_arg_timer(timer) \
101 if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
102 printk(KERN_ERR "open_pic.c:%d: invalid timer %d\n", __LINE__, timer);
103 #define check_arg_vec(vec) \
104 if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
105 printk(KERN_ERR "open_pic.c:%d: invalid vector %d\n", __LINE__, vec);
106 #define check_arg_pri(pri) \
107 if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
108 printk(KERN_ERR "open_pic.c:%d: invalid priority %d\n", __LINE__, pri);
110 * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
111 * data has probably been corrupted and we're going to panic or deadlock later
114 #define check_arg_irq(irq) \
115 if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ \
116 printk(KERN_ERR "open_pic.c:%d: invalid irq %d\n", __LINE__, irq); \
118 #define check_arg_cpu(cpu) \
119 if (cpu < 0 || cpu >= OPENPIC_MAX_PROCESSORS){ \
120 printk(KERN_ERR "open_pic.c:%d: invalid cpu %d\n", __LINE__, cpu); \
123 #define check_arg_ipi(ipi) do {} while (0)
124 #define check_arg_timer(timer) do {} while (0)
125 #define check_arg_vec(vec) do {} while (0)
126 #define check_arg_pri(pri) do {} while (0)
127 #define check_arg_irq(irq) do {} while (0)
128 #define check_arg_cpu(cpu) do {} while (0)
131 #define GET_ISU(source) ISU[(source) >> 4][(source) & 0xf]
133 void __init openpic_init_IRQ(void)
135 struct device_node *np;
138 unsigned char* chrp_int_ack_special = 0;
139 unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
141 #if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
142 struct device_node *kbd;
145 if (!(np = find_devices("pci"))
146 || !(addrp = (unsigned int *)
147 get_property(np, "8259-interrupt-acknowledge", NULL)))
148 printk(KERN_ERR "Cannot find pci to get ack address\n");
150 chrp_int_ack_special = (unsigned char *)
151 __ioremap(addrp[prom_n_addr_cells(np)-1], 1, _PAGE_NO_CACHE);
152 /* hydra still sets OpenPIC_InitSenses to a static set of values */
153 if (OpenPIC_InitSenses == NULL) {
154 prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS);
155 OpenPIC_InitSenses = init_senses;
156 OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS;
158 openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq);
159 for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ )
160 irq_desc[i].handler = &i8259_pic;
163 static inline u_int openpic_read(volatile u_int *addr)
171 static inline void openpic_write(volatile u_int *addr, u_int val)
176 static inline u_int openpic_readfield(volatile u_int *addr, u_int mask)
178 u_int val = openpic_read(addr);
182 static inline void openpic_writefield(volatile u_int *addr, u_int mask,
185 u_int val = openpic_read(addr);
186 openpic_write(addr, (val & ~mask) | (field & mask));
189 static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
191 openpic_writefield(addr, mask, 0);
194 static inline void openpic_setfield(volatile u_int *addr, u_int mask)
196 openpic_writefield(addr, mask, mask);
199 static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
202 unsigned int loops = 100000;
204 openpic_setfield(addr, OPENPIC_MASK);
205 while (openpic_read(addr) & OPENPIC_ACTIVITY) {
207 printk(KERN_ERR "openpic_safe_writefield timeout\n");
211 openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
215 static u_int openpic_read_IPI(volatile u_int* addr)
219 if (broken_ipi_registers)
220 /* yes this is right ... bug, feature, you decide! -- tgall */
228 static void openpic_test_broken_IPI(void)
232 openpic_write(&OpenPIC->Global.IPI_Vector_Priority(0), OPENPIC_MASK);
233 t = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(0));
234 if (t == le32_to_cpu(OPENPIC_MASK)) {
235 printk(KERN_INFO "OpenPIC reversed IPI registers detected\n");
236 broken_ipi_registers = 1;
240 /* because of the power3 be / le above, this is needed */
241 static inline void openpic_writefield_IPI(volatile u_int* addr, u_int mask, u_int field)
243 u_int val = openpic_read_IPI(addr);
244 openpic_write(addr, (val & ~mask) | (field & mask));
247 static inline void openpic_clearfield_IPI(volatile u_int *addr, u_int mask)
249 openpic_writefield_IPI(addr, mask, 0);
252 static inline void openpic_setfield_IPI(volatile u_int *addr, u_int mask)
254 openpic_writefield_IPI(addr, mask, mask);
257 static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int field)
259 unsigned int loops = 100000;
261 openpic_setfield_IPI(addr, OPENPIC_MASK);
263 /* wait until it's not in use */
264 /* BenH: Is this code really enough ? I would rather check the result
265 * and eventually retry ...
267 while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY) {
269 printk(KERN_ERR "openpic_safe_writefield timeout\n");
274 openpic_writefield_IPI(addr, mask, field | OPENPIC_MASK);
276 #endif /* CONFIG_SMP */
278 void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
279 int programmer_switch_irq)
286 printk(KERN_INFO "No OpenPIC found !\n");
289 OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
291 ppc64_boot_msg(0x20, "OpenPic Init");
293 t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
294 switch (t & OPENPIC_FEATURE_VERSION_MASK) {
308 NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
309 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
310 NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
311 OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
312 printk(KERN_INFO "OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n",
313 version, NumProcessors, NumSources, OpenPIC);
314 timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
316 printk(KERN_INFO "OpenPIC timer frequency is %d.%06d MHz\n",
317 timerfreq / 1000000, timerfreq % 1000000);
322 open_pic_irq_offset = offset;
323 chrp_int_ack_special = (volatile unsigned char*)chrp_ack;
327 /* Initialize timer interrupts */
328 ppc64_boot_msg(0x21, "OpenPic Timer");
329 for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
330 /* Disabled, Priority 0 */
331 openpic_inittimer(i, 0, openpic_vec_timer+i);
333 openpic_maptimer(i, 0);
337 /* Initialize IPI interrupts */
338 ppc64_boot_msg(0x22, "OpenPic IPI");
339 openpic_test_broken_IPI();
340 for (i = 0; i < OPENPIC_NUM_IPI; i++) {
341 /* Disabled, Priority 10..13 */
342 openpic_initipi(i, 10+i, openpic_vec_ipi+i);
343 /* IPIs are per-CPU */
344 irq_desc[openpic_vec_ipi+i].status |= IRQ_PER_CPU;
345 irq_desc[openpic_vec_ipi+i].handler = &open_pic_ipi;
349 /* Initialize external interrupts */
350 ppc64_boot_msg(0x23, "OpenPic Ext");
352 openpic_set_priority(0xf);
354 /* SIOint (8259 cascade) is special */
356 openpic_initirq(0, 8, offset, 1, 1);
357 openpic_mapirq(0, 1 << boot_cpuid);
360 /* Init all external sources */
361 for (i = 1; i < NumSources; i++) {
364 /* the bootloader may have left it enabled (bad !) */
365 openpic_disable_irq(i+offset);
367 pri = (i == programmer_switch_irq)? 9: 8;
368 sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
370 irq_desc[i+offset].status = IRQ_LEVEL;
372 /* Enabled, Priority 8 or 9 */
373 openpic_initirq(i, pri, i+offset, !sense, sense);
375 openpic_mapirq(i, 1 << boot_cpuid);
378 /* Init descriptors */
379 for (i = offset; i < NumSources + offset; i++)
380 irq_desc[i].handler = &open_pic;
382 /* Initialize the spurious interrupt */
383 ppc64_boot_msg(0x24, "OpenPic Spurious");
384 openpic_set_spurious(openpic_vec_spurious);
386 openpic_set_priority(0);
387 openpic_disable_8259_pass_through();
389 ppc64_boot_msg(0x25, "OpenPic Done");
393 * We cant do this in init_IRQ because we need the memory subsystem up for
396 static int __init openpic_setup_i8259(void)
398 if (naca->interrupt_controller == IC_OPEN_PIC) {
399 /* Initialize the cascade */
400 if (request_irq(NUM_8259_INTERRUPTS, no_action, SA_INTERRUPT,
401 "82c59 cascade", NULL))
402 printk(KERN_ERR "Unable to get OpenPIC IRQ 0 for cascade\n");
408 arch_initcall(openpic_setup_i8259);
410 void openpic_setup_ISU(int isu_num, unsigned long addr)
412 if (isu_num >= OPENPIC_MAX_ISU)
414 ISU[isu_num] = (OpenPIC_SourcePtr) __ioremap(addr, 0x400, _PAGE_NO_CACHE);
415 if (isu_num >= NumISUs)
416 NumISUs = isu_num + 1;
421 /* Use /interrupt-controller/reg and
422 * /interrupt-controller/interrupt-ranges from OF device tree
423 * the ISU array is setup in chrp_pci.c in ibm_add_bridges
428 /* basically each ISU is a bus, and this assumes that
429 * open_pic_isu_count interrupts per bus are possible
430 * ISU == Interrupt Source
432 NumSources = NumISUs * 0x10;
433 openpic_vec_ipi = NumSources + open_pic_irq_offset;
434 openpic_vec_timer = openpic_vec_ipi + OPENPIC_NUM_IPI;
435 openpic_vec_spurious = openpic_vec_timer + OPENPIC_NUM_TIMERS;
438 static inline void openpic_reset(void)
440 openpic_setfield(&OpenPIC->Global.Global_Configuration0,
441 OPENPIC_CONFIG_RESET);
444 static inline void openpic_enable_8259_pass_through(void)
446 openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
447 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
450 static void openpic_disable_8259_pass_through(void)
452 openpic_setfield(&OpenPIC->Global.Global_Configuration0,
453 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
457 * Find out the current interrupt
459 static u_int openpic_irq(void)
465 vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
466 OPENPIC_VECTOR_MASK);
470 static void openpic_eoi(void)
475 openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
476 /* Handle PCI write posting */
477 (void)openpic_read(&OpenPIC->THIS_CPU.EOI);
481 static inline u_int openpic_get_priority(void)
486 return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
487 OPENPIC_CURRENT_TASK_PRIORITY_MASK);
490 static void openpic_set_priority(u_int pri)
496 openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
497 OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
501 * Get/set the spurious vector
503 static inline u_int openpic_get_spurious(void)
505 return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
506 OPENPIC_VECTOR_MASK);
509 static void openpic_set_spurious(u_int vec)
512 openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
516 void openpic_init_processor(u_int cpumask)
518 openpic_write(&OpenPIC->Global.Processor_Initialization,
519 cpumask & cpu_online_map);
524 * Initialize an interprocessor interrupt (and disable it)
526 * ipi: OpenPIC interprocessor interrupt number
527 * pri: interrupt source priority
528 * vec: the vector it will produce
530 static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec)
535 openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi),
536 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
537 (pri << OPENPIC_PRIORITY_SHIFT) | vec);
541 * Send an IPI to one or more CPUs
543 * Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
544 * and not a system-wide interrupt number
546 void openpic_cause_IPI(u_int ipi, u_int cpumask)
552 openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
553 cpumask & cpu_online_map);
556 void openpic_request_IPIs(void)
561 * Make sure this matches what is defined in smp.c for
562 * smp_message_{pass|recv}() or what shows up in
563 * /proc/interrupts will be wrong!!! --Troy */
568 /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */
569 request_irq(openpic_vec_ipi, openpic_ipi_action, SA_INTERRUPT,
570 "IPI0 (call function)", 0);
571 request_irq(openpic_vec_ipi+1, openpic_ipi_action, SA_INTERRUPT,
572 "IPI1 (reschedule)", 0);
573 request_irq(openpic_vec_ipi+2, openpic_ipi_action, SA_INTERRUPT,
574 "IPI2 (invalidate tlb)", 0);
575 request_irq(openpic_vec_ipi+3, openpic_ipi_action, SA_INTERRUPT,
576 "IPI3 (xmon break)", 0);
578 for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
579 openpic_enable_ipi(openpic_vec_ipi+i);
583 * Do per-cpu setup for SMP systems.
585 * Get IPI's working and start taking interrupts.
588 static spinlock_t openpic_setup_lock __devinitdata = SPIN_LOCK_UNLOCKED;
590 void __devinit do_openpic_setup_cpu(void)
592 #ifdef CONFIG_IRQ_ALL_CPUS
594 u32 msk = 1 << smp_processor_id();
597 spin_lock(&openpic_setup_lock);
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
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);
611 spin_unlock(&openpic_setup_lock);
613 #endif /* CONFIG_SMP */
616 * Initialize a timer interrupt (and disable it)
618 * timer: OpenPIC timer number
619 * pri: interrupt source priority
620 * vec: the vector it will produce
622 static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec)
624 check_arg_timer(timer);
627 openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
628 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
629 (pri << OPENPIC_PRIORITY_SHIFT) | vec);
633 * Map a timer interrupt to one or more CPUs
635 static void __init openpic_maptimer(u_int timer, u_int cpumask)
637 check_arg_timer(timer);
638 openpic_write(&OpenPIC->Global.Timer[timer].Destination,
639 cpumask & cpu_online_map);
645 * All functions below take an offset'ed irq argument
651 * Enable/disable an external interrupt source
653 * Externally called, irq is an offseted system-wide interrupt number
655 static void openpic_enable_irq(u_int irq)
657 unsigned int loops = 100000;
660 openpic_clearfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
661 /* make sure mask gets to controller before we return to user */
664 printk(KERN_ERR "openpic_enable_irq timeout\n");
668 mb(); /* sync is probably useless here */
669 } while(openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
673 static void openpic_disable_irq(u_int irq)
676 unsigned int loops = 100000;
680 openpic_setfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
681 /* make sure mask gets to controller before we return to user */
684 printk(KERN_ERR "openpic_disable_irq timeout\n");
688 mb(); /* sync is probably useless here */
689 vp = openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
690 OPENPIC_MASK | OPENPIC_ACTIVITY);
691 } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
696 * Enable/disable an IPI interrupt source
698 * Externally called, irq is an offseted system-wide interrupt number
700 void openpic_enable_ipi(u_int irq)
702 irq -= openpic_vec_ipi;
704 openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
707 void openpic_disable_ipi(u_int irq)
709 /* NEVER disable an IPI... that's just plain wrong! */
715 * Initialize an interrupt source (and disable it!)
717 * irq: OpenPIC interrupt number
718 * pri: interrupt source priority
719 * vec: the vector it will produce
720 * pol: polarity (1 for positive, 0 for negative)
721 * sense: 1 for level, 0 for edge
723 static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
725 openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
726 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
727 OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
728 (pri << OPENPIC_PRIORITY_SHIFT) | vec |
729 (pol ? OPENPIC_POLARITY_POSITIVE :
730 OPENPIC_POLARITY_NEGATIVE) |
731 (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
735 * Map an interrupt source to one or more CPUs
737 static void openpic_mapirq(u_int irq, u_int physmask)
739 openpic_write(&GET_ISU(irq).Destination, physmask);
743 * Set the sense for an interrupt source (and disable it!)
745 * sense: 1 for level, 0 for edge
747 static inline void openpic_set_sense(u_int irq, int sense)
749 openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
751 (sense ? OPENPIC_SENSE_LEVEL : 0));
754 static void openpic_end_irq(unsigned int irq_nr)
756 if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
760 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
762 openpic_mapirq(irq_nr - open_pic_irq_offset, cpumask & cpu_online_map);
766 static void openpic_end_ipi(unsigned int irq_nr)
769 * IPIs are marked IRQ_PER_CPU. This has the side effect of
770 * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from
771 * applying to them. We EOI them late to avoid re-entering.
772 * We mark IPI's with SA_INTERRUPT as they must run with
778 static irqreturn_t openpic_ipi_action(int cpl, void *dev_id,
779 struct pt_regs *regs)
781 smp_message_recv(cpl-openpic_vec_ipi, regs);
785 #endif /* CONFIG_SMP */
787 int openpic_get_irq(struct pt_regs *regs)
789 extern int i8259_irq(int cpu);
791 int irq = openpic_irq();
793 /* Management of the cascade should be moved out of here */
794 if (open_pic_irq_offset && irq == open_pic_irq_offset)
797 * This magic address generates a PCI IACK cycle.
799 if ( chrp_int_ack_special )
800 irq = *chrp_int_ack_special;
802 irq = i8259_irq( smp_processor_id() );
805 if (irq == openpic_vec_spurious)