2 * Copyright (C) 1997 Geert Uytterhoeven
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file COPYING in the main directory of this archive
8 * This is a duplicate of open_pic.c that deals with U3s MPIC on
9 * G5 PowerMacs. It's the same file except it's using big endian
13 #include <linux/config.h>
14 #include <linux/types.h>
15 #include <linux/kernel.h>
16 #include <linux/sched.h>
17 #include <linux/init.h>
18 #include <linux/interrupt.h>
19 #include <linux/sysdev.h>
20 #include <linux/errno.h>
21 #include <asm/ptrace.h>
22 #include <asm/signal.h>
25 #include <asm/sections.h>
26 #include <asm/open_pic.h>
27 #include <asm/i8259.h>
28 #include <asm/machdep.h>
30 #include "open_pic_defs.h"
33 static volatile struct OpenPIC
*OpenPIC2
= NULL
;
35 * We define OpenPIC_InitSenses table thusly:
36 * bit 0x1: sense, 0 for edge and 1 for level.
37 * bit 0x2: polarity, 0 for negative, 1 for positive.
39 extern u_int OpenPIC_NumInitSenses
;
40 extern u_char
*OpenPIC_InitSenses
;
41 extern int use_of_interrupt_tree
;
43 static u_int NumProcessors
;
44 static u_int NumSources
;
45 static int open_pic2_irq_offset
;
46 static volatile OpenPIC_Source
*ISR
[NR_IRQS
];
48 /* Global Operations */
49 static void openpic2_disable_8259_pass_through(void);
50 static void openpic2_set_priority(u_int pri
);
51 static void openpic2_set_spurious(u_int vector
);
53 /* Timer Interrupts */
54 static void openpic2_inittimer(u_int timer
, u_int pri
, u_int vector
);
55 static void openpic2_maptimer(u_int timer
, u_int cpumask
);
57 /* Interrupt Sources */
58 static void openpic2_enable_irq(u_int irq
);
59 static void openpic2_disable_irq(u_int irq
);
60 static void openpic2_initirq(u_int irq
, u_int pri
, u_int vector
, int polarity
,
62 static void openpic2_mapirq(u_int irq
, u_int cpumask
, u_int keepmask
);
65 * These functions are not used but the code is kept here
66 * for completeness and future reference.
68 static void openpic2_reset(void);
70 static void openpic2_enable_8259_pass_through(void);
71 static u_int
openpic2_get_priority(void);
72 static u_int
openpic2_get_spurious(void);
73 static void openpic2_set_sense(u_int irq
, int sense
);
77 * Description of the openpic for the higher-level irq code
79 static void openpic2_end_irq(unsigned int irq_nr
);
80 static void openpic2_ack_irq(unsigned int irq_nr
);
82 struct hw_interrupt_type open_pic2
= {
83 .typename
= " OpenPIC2 ",
84 .enable
= openpic2_enable_irq
,
85 .disable
= openpic2_disable_irq
,
86 .ack
= openpic2_ack_irq
,
87 .end
= openpic2_end_irq
,
91 * Accesses to the current processor's openpic registers
92 * On cascaded controller, this is only CPU 0
94 #define THIS_CPU Processor[0]
96 #define CHECK_THIS_CPU
99 #define check_arg_ipi(ipi) \
100 if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
101 printk("open_pic.c:%d: illegal ipi %d\n", __LINE__, ipi);
102 #define check_arg_timer(timer) \
103 if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
104 printk("open_pic.c:%d: illegal timer %d\n", __LINE__, timer);
105 #define check_arg_vec(vec) \
106 if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
107 printk("open_pic.c:%d: illegal vector %d\n", __LINE__, vec);
108 #define check_arg_pri(pri) \
109 if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
110 printk("open_pic.c:%d: illegal priority %d\n", __LINE__, pri);
112 * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
113 * data has probably been corrupted and we're going to panic or deadlock later
116 extern unsigned long* _get_SP(void);
117 #define check_arg_irq(irq) \
118 if (irq < open_pic2_irq_offset || irq >= NumSources+open_pic2_irq_offset \
119 || ISR[irq - open_pic2_irq_offset] == 0) { \
120 printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
121 /*print_backtrace(_get_SP());*/ }
122 #define check_arg_cpu(cpu) \
123 if (cpu < 0 || cpu >= NumProcessors){ \
124 printk("open_pic2.c:%d: illegal cpu %d\n", __LINE__, cpu); \
125 /*print_backtrace(_get_SP());*/ }
127 #define check_arg_ipi(ipi) do {} while (0)
128 #define check_arg_timer(timer) do {} while (0)
129 #define check_arg_vec(vec) do {} while (0)
130 #define check_arg_pri(pri) do {} while (0)
131 #define check_arg_irq(irq) do {} while (0)
132 #define check_arg_cpu(cpu) do {} while (0)
135 static u_int
openpic2_read(volatile u_int
*addr
)
143 static inline void openpic2_write(volatile u_int
*addr
, u_int val
)
148 static inline u_int
openpic2_readfield(volatile u_int
*addr
, u_int mask
)
150 u_int val
= openpic2_read(addr
);
154 inline void openpic2_writefield(volatile u_int
*addr
, u_int mask
,
157 u_int val
= openpic2_read(addr
);
158 openpic2_write(addr
, (val
& ~mask
) | (field
& mask
));
161 static inline void openpic2_clearfield(volatile u_int
*addr
, u_int mask
)
163 openpic2_writefield(addr
, mask
, 0);
166 static inline void openpic2_setfield(volatile u_int
*addr
, u_int mask
)
168 openpic2_writefield(addr
, mask
, mask
);
171 static void openpic2_safe_writefield(volatile u_int
*addr
, u_int mask
,
174 openpic2_setfield(addr
, OPENPIC_MASK
);
175 while (openpic2_read(addr
) & OPENPIC_ACTIVITY
);
176 openpic2_writefield(addr
, mask
| OPENPIC_MASK
, field
| OPENPIC_MASK
);
179 static void openpic2_reset(void)
181 openpic2_setfield(&OpenPIC2
->Global
.Global_Configuration0
,
182 OPENPIC_CONFIG_RESET
);
183 while (openpic2_readfield(&OpenPIC2
->Global
.Global_Configuration0
,
184 OPENPIC_CONFIG_RESET
))
188 void __init
openpic2_set_sources(int first_irq
, int num_irqs
, void *first_ISR
)
190 volatile OpenPIC_Source
*src
= first_ISR
;
193 last_irq
= first_irq
+ num_irqs
;
194 if (last_irq
> NumSources
)
195 NumSources
= last_irq
;
197 src
= &((struct OpenPIC
*)OpenPIC2_Addr
)->Source
[first_irq
];
198 for (i
= first_irq
; i
< last_irq
; ++i
, ++src
)
203 * The `offset' parameter defines where the interrupts handled by the
204 * OpenPIC start in the space of interrupt numbers that the kernel knows
205 * about. In other words, the OpenPIC's IRQ0 is numbered `offset' in the
206 * kernel's interrupt numbering scheme.
207 * We assume there is only one OpenPIC.
209 void __init
openpic2_init(int offset
)
215 if (!OpenPIC2_Addr
) {
216 printk("No OpenPIC2 found !\n");
219 OpenPIC2
= (volatile struct OpenPIC
*)OpenPIC2_Addr
;
221 if (ppc_md
.progress
) ppc_md
.progress("openpic: enter", 0x122);
223 t
= openpic2_read(&OpenPIC2
->Global
.Feature_Reporting0
);
224 switch (t
& OPENPIC_FEATURE_VERSION_MASK
) {
238 NumProcessors
= ((t
& OPENPIC_FEATURE_LAST_PROCESSOR_MASK
) >>
239 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT
) + 1;
241 openpic2_set_sources(0,
242 ((t
& OPENPIC_FEATURE_LAST_SOURCE_MASK
) >>
243 OPENPIC_FEATURE_LAST_SOURCE_SHIFT
) + 1,
245 printk("OpenPIC (2) Version %s (%d CPUs and %d IRQ sources) at %p\n",
246 version
, NumProcessors
, NumSources
, OpenPIC2
);
247 timerfreq
= openpic2_read(&OpenPIC2
->Global
.Timer_Frequency
);
249 printk("OpenPIC timer frequency is %d.%06d MHz\n",
250 timerfreq
/ 1000000, timerfreq
% 1000000);
252 open_pic2_irq_offset
= offset
;
254 /* Initialize timer interrupts */
255 if ( ppc_md
.progress
) ppc_md
.progress("openpic2: timer",0x3ba);
256 for (i
= 0; i
< OPENPIC_NUM_TIMERS
; i
++) {
257 /* Disabled, Priority 0 */
258 openpic2_inittimer(i
, 0, OPENPIC2_VEC_TIMER
+i
+offset
);
260 openpic2_maptimer(i
, 0);
263 /* Initialize external interrupts */
264 if (ppc_md
.progress
) ppc_md
.progress("openpic2: external",0x3bc);
266 openpic2_set_priority(0xf);
268 /* Init all external sources, including possibly the cascade. */
269 for (i
= 0; i
< NumSources
; i
++) {
275 /* the bootloader may have left it enabled (bad !) */
276 openpic2_disable_irq(i
+offset
);
278 sense
= (i
< OpenPIC_NumInitSenses
)? OpenPIC_InitSenses
[i
]: \
279 (IRQ_SENSE_LEVEL
| IRQ_POLARITY_NEGATIVE
);
281 if (sense
& IRQ_SENSE_MASK
)
282 irq_desc
[i
+offset
].status
= IRQ_LEVEL
;
284 /* Enabled, Priority 8 */
285 openpic2_initirq(i
, 8, i
+offset
, (sense
& IRQ_POLARITY_MASK
),
286 (sense
& IRQ_SENSE_MASK
));
288 openpic2_mapirq(i
, 1<<0, 0);
291 /* Init descriptors */
292 for (i
= offset
; i
< NumSources
+ offset
; i
++)
293 irq_desc
[i
].handler
= &open_pic2
;
295 /* Initialize the spurious interrupt */
296 if (ppc_md
.progress
) ppc_md
.progress("openpic2: spurious",0x3bd);
297 openpic2_set_spurious(OPENPIC2_VEC_SPURIOUS
+offset
);
299 openpic2_disable_8259_pass_through();
300 openpic2_set_priority(0);
302 if (ppc_md
.progress
) ppc_md
.progress("openpic2: exit",0x222);
306 static void openpic2_enable_8259_pass_through(void)
308 openpic2_clearfield(&OpenPIC2
->Global
.Global_Configuration0
,
309 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE
);
313 /* This can't be __init, it is used in openpic_sleep_restore_intrs */
314 static void openpic2_disable_8259_pass_through(void)
316 openpic2_setfield(&OpenPIC2
->Global
.Global_Configuration0
,
317 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE
);
321 * Find out the current interrupt
323 u_int
openpic2_irq(void)
329 vec
= openpic2_readfield(&OpenPIC2
->THIS_CPU
.Interrupt_Acknowledge
,
330 OPENPIC_VECTOR_MASK
);
334 void openpic2_eoi(void)
339 openpic2_write(&OpenPIC2
->THIS_CPU
.EOI
, 0);
340 /* Handle PCI write posting */
341 (void)openpic2_read(&OpenPIC2
->THIS_CPU
.EOI
);
345 static u_int
openpic2_get_priority(void)
350 return openpic2_readfield(&OpenPIC2
->THIS_CPU
.Current_Task_Priority
,
351 OPENPIC_CURRENT_TASK_PRIORITY_MASK
);
355 static void __init
openpic2_set_priority(u_int pri
)
361 openpic2_writefield(&OpenPIC2
->THIS_CPU
.Current_Task_Priority
,
362 OPENPIC_CURRENT_TASK_PRIORITY_MASK
, pri
);
366 * Get/set the spurious vector
369 static u_int
openpic2_get_spurious(void)
371 return openpic2_readfield(&OpenPIC2
->Global
.Spurious_Vector
,
372 OPENPIC_VECTOR_MASK
);
376 /* This can't be __init, it is used in openpic_sleep_restore_intrs */
377 static void openpic2_set_spurious(u_int vec
)
380 openpic2_writefield(&OpenPIC2
->Global
.Spurious_Vector
, OPENPIC_VECTOR_MASK
,
384 static DEFINE_SPINLOCK(openpic2_setup_lock
);
387 * Initialize a timer interrupt (and disable it)
389 * timer: OpenPIC timer number
390 * pri: interrupt source priority
391 * vec: the vector it will produce
393 static void __init
openpic2_inittimer(u_int timer
, u_int pri
, u_int vec
)
395 check_arg_timer(timer
);
398 openpic2_safe_writefield(&OpenPIC2
->Global
.Timer
[timer
].Vector_Priority
,
399 OPENPIC_PRIORITY_MASK
| OPENPIC_VECTOR_MASK
,
400 (pri
<< OPENPIC_PRIORITY_SHIFT
) | vec
);
404 * Map a timer interrupt to one or more CPUs
406 static void __init
openpic2_maptimer(u_int timer
, u_int cpumask
)
408 check_arg_timer(timer
);
409 openpic2_write(&OpenPIC2
->Global
.Timer
[timer
].Destination
,
414 * Initalize the interrupt source which will generate an NMI.
415 * This raises the interrupt's priority from 8 to 9.
417 * irq: The logical IRQ which generates an NMI.
420 openpic2_init_nmi_irq(u_int irq
)
423 openpic2_safe_writefield(&ISR
[irq
- open_pic2_irq_offset
]->Vector_Priority
,
424 OPENPIC_PRIORITY_MASK
,
425 9 << OPENPIC_PRIORITY_SHIFT
);
430 * All functions below take an offset'ed irq argument
436 * Enable/disable an external interrupt source
438 * Externally called, irq is an offseted system-wide interrupt number
440 static void openpic2_enable_irq(u_int irq
)
445 vpp
= &ISR
[irq
- open_pic2_irq_offset
]->Vector_Priority
;
446 openpic2_clearfield(vpp
, OPENPIC_MASK
);
447 /* make sure mask gets to controller before we return to user */
449 mb(); /* sync is probably useless here */
450 } while (openpic2_readfield(vpp
, OPENPIC_MASK
));
453 static void openpic2_disable_irq(u_int irq
)
459 vpp
= &ISR
[irq
- open_pic2_irq_offset
]->Vector_Priority
;
460 openpic2_setfield(vpp
, OPENPIC_MASK
);
461 /* make sure mask gets to controller before we return to user */
463 mb(); /* sync is probably useless here */
464 vp
= openpic2_readfield(vpp
, OPENPIC_MASK
| OPENPIC_ACTIVITY
);
465 } while((vp
& OPENPIC_ACTIVITY
) && !(vp
& OPENPIC_MASK
));
470 * Initialize an interrupt source (and disable it!)
472 * irq: OpenPIC interrupt number
473 * pri: interrupt source priority
474 * vec: the vector it will produce
475 * pol: polarity (1 for positive, 0 for negative)
476 * sense: 1 for level, 0 for edge
479 openpic2_initirq(u_int irq
, u_int pri
, u_int vec
, int pol
, int sense
)
481 openpic2_safe_writefield(&ISR
[irq
]->Vector_Priority
,
482 OPENPIC_PRIORITY_MASK
| OPENPIC_VECTOR_MASK
|
483 OPENPIC_SENSE_MASK
| OPENPIC_POLARITY_MASK
,
484 (pri
<< OPENPIC_PRIORITY_SHIFT
) | vec
|
485 (pol
? OPENPIC_POLARITY_POSITIVE
:
486 OPENPIC_POLARITY_NEGATIVE
) |
487 (sense
? OPENPIC_SENSE_LEVEL
: OPENPIC_SENSE_EDGE
));
491 * Map an interrupt source to one or more CPUs
493 static void openpic2_mapirq(u_int irq
, u_int physmask
, u_int keepmask
)
498 physmask
|= openpic2_read(&ISR
[irq
]->Destination
) & keepmask
;
499 openpic2_write(&ISR
[irq
]->Destination
, physmask
);
504 * Set the sense for an interrupt source (and disable it!)
506 * sense: 1 for level, 0 for edge
508 static void openpic2_set_sense(u_int irq
, int sense
)
511 openpic2_safe_writefield(&ISR
[irq
]->Vector_Priority
,
513 (sense
? OPENPIC_SENSE_LEVEL
: 0));
517 /* No spinlocks, should not be necessary with the OpenPIC
518 * (1 register = 1 interrupt and we have the desc lock).
520 static void openpic2_ack_irq(unsigned int irq_nr
)
522 openpic2_disable_irq(irq_nr
);
526 static void openpic2_end_irq(unsigned int irq_nr
)
528 if (!(irq_desc
[irq_nr
].status
& (IRQ_DISABLED
|IRQ_INPROGRESS
)))
529 openpic2_enable_irq(irq_nr
);
533 openpic2_get_irq(struct pt_regs
*regs
)
535 int irq
= openpic2_irq();
537 if (irq
== (OPENPIC2_VEC_SPURIOUS
+ open_pic2_irq_offset
))
545 * We implement the IRQ controller as a sysdev and put it
546 * to sleep at powerdown stage (the callback is named suspend,
547 * but it's old semantics, for the Device Model, it's really
548 * powerdown). The possible problem is that another sysdev that
549 * happens to be suspend after this one will have interrupts off,
550 * that may be an issue... For now, this isn't an issue on pmac
554 static u32 save_ipi_vp
[OPENPIC_NUM_IPI
];
555 static u32 save_irq_src_vp
[OPENPIC_MAX_SOURCES
];
556 static u32 save_irq_src_dest
[OPENPIC_MAX_SOURCES
];
557 static u32 save_cpu_task_pri
[OPENPIC_MAX_PROCESSORS
];
558 static int openpic_suspend_count
;
560 static void openpic2_cached_enable_irq(u_int irq
)
563 save_irq_src_vp
[irq
- open_pic2_irq_offset
] &= ~OPENPIC_MASK
;
566 static void openpic2_cached_disable_irq(u_int irq
)
569 save_irq_src_vp
[irq
- open_pic2_irq_offset
] |= OPENPIC_MASK
;
572 /* WARNING: Can be called directly by the cpufreq code with NULL parameter,
573 * we need something better to deal with that... Maybe switch to S1 for
576 int openpic2_suspend(struct sys_device
*sysdev
, pm_message_t state
)
581 spin_lock_irqsave(&openpic2_setup_lock
, flags
);
583 if (openpic_suspend_count
++ > 0) {
584 spin_unlock_irqrestore(&openpic2_setup_lock
, flags
);
588 open_pic2
.enable
= openpic2_cached_enable_irq
;
589 open_pic2
.disable
= openpic2_cached_disable_irq
;
591 for (i
=0; i
<NumProcessors
; i
++) {
592 save_cpu_task_pri
[i
] = openpic2_read(&OpenPIC2
->Processor
[i
].Current_Task_Priority
);
593 openpic2_writefield(&OpenPIC2
->Processor
[i
].Current_Task_Priority
,
594 OPENPIC_CURRENT_TASK_PRIORITY_MASK
, 0xf);
597 for (i
=0; i
<OPENPIC_NUM_IPI
; i
++)
598 save_ipi_vp
[i
] = openpic2_read(&OpenPIC2
->Global
.IPI_Vector_Priority(i
));
599 for (i
=0; i
<NumSources
; i
++) {
602 save_irq_src_vp
[i
] = openpic2_read(&ISR
[i
]->Vector_Priority
) & ~OPENPIC_ACTIVITY
;
603 save_irq_src_dest
[i
] = openpic2_read(&ISR
[i
]->Destination
);
606 spin_unlock_irqrestore(&openpic2_setup_lock
, flags
);
611 /* WARNING: Can be called directly by the cpufreq code with NULL parameter,
612 * we need something better to deal with that... Maybe switch to S1 for
615 int openpic2_resume(struct sys_device
*sysdev
)
619 u32 vppmask
= OPENPIC_PRIORITY_MASK
| OPENPIC_VECTOR_MASK
|
620 OPENPIC_SENSE_MASK
| OPENPIC_POLARITY_MASK
|
623 spin_lock_irqsave(&openpic2_setup_lock
, flags
);
625 if ((--openpic_suspend_count
) > 0) {
626 spin_unlock_irqrestore(&openpic2_setup_lock
, flags
);
632 /* OpenPIC sometimes seem to need some time to be fully back up... */
634 openpic2_set_spurious(OPENPIC2_VEC_SPURIOUS
+open_pic2_irq_offset
);
635 } while(openpic2_readfield(&OpenPIC2
->Global
.Spurious_Vector
, OPENPIC_VECTOR_MASK
)
636 != (OPENPIC2_VEC_SPURIOUS
+ open_pic2_irq_offset
));
638 openpic2_disable_8259_pass_through();
640 for (i
=0; i
<OPENPIC_NUM_IPI
; i
++)
641 openpic2_write(&OpenPIC2
->Global
.IPI_Vector_Priority(i
),
643 for (i
=0; i
<NumSources
; i
++) {
646 openpic2_write(&ISR
[i
]->Destination
, save_irq_src_dest
[i
]);
647 openpic2_write(&ISR
[i
]->Vector_Priority
, save_irq_src_vp
[i
]);
648 /* make sure mask gets to controller before we return to user */
650 openpic2_write(&ISR
[i
]->Vector_Priority
, save_irq_src_vp
[i
]);
651 } while (openpic2_readfield(&ISR
[i
]->Vector_Priority
, vppmask
)
652 != (save_irq_src_vp
[i
] & vppmask
));
654 for (i
=0; i
<NumProcessors
; i
++)
655 openpic2_write(&OpenPIC2
->Processor
[i
].Current_Task_Priority
,
656 save_cpu_task_pri
[i
]);
658 open_pic2
.enable
= openpic2_enable_irq
;
659 open_pic2
.disable
= openpic2_disable_irq
;
661 spin_unlock_irqrestore(&openpic2_setup_lock
, flags
);
666 #endif /* CONFIG_PM */
669 static struct sysdev_class openpic2_sysclass
= {
670 set_kset_name("openpic2"),
673 static struct sys_device device_openpic2
= {
675 .cls
= &openpic2_sysclass
,
678 static struct sysdev_driver driver_openpic2
= {
680 .suspend
= &openpic2_suspend
,
681 .resume
= &openpic2_resume
,
682 #endif /* CONFIG_PM */
685 static int __init
init_openpic2_sysfs(void)
691 printk(KERN_DEBUG
"Registering openpic2 with sysfs...\n");
692 rc
= sysdev_class_register(&openpic2_sysclass
);
694 printk(KERN_ERR
"Failed registering openpic sys class\n");
697 rc
= sysdev_register(&device_openpic2
);
699 printk(KERN_ERR
"Failed registering openpic sys device\n");
702 rc
= sysdev_driver_register(&openpic2_sysclass
, &driver_openpic2
);
704 printk(KERN_ERR
"Failed registering openpic sys driver\n");
710 subsys_initcall(init_openpic2_sysfs
);