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/types.h>
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/init.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>
24 #include <asm/sections.h>
25 #include <asm/open_pic.h>
26 #include <asm/i8259.h>
27 #include <asm/machdep.h>
29 #include "open_pic_defs.h"
32 static volatile struct OpenPIC
*OpenPIC2
= NULL
;
34 * We define OpenPIC_InitSenses table thusly:
35 * bit 0x1: sense, 0 for edge and 1 for level.
36 * bit 0x2: polarity, 0 for negative, 1 for positive.
38 extern u_int OpenPIC_NumInitSenses
;
39 extern u_char
*OpenPIC_InitSenses
;
40 extern int use_of_interrupt_tree
;
42 static u_int NumProcessors
;
43 static u_int NumSources
;
44 static int open_pic2_irq_offset
;
45 static volatile OpenPIC_Source
*ISR
[NR_IRQS
];
47 /* Global Operations */
48 static void openpic2_disable_8259_pass_through(void);
49 static void openpic2_set_priority(u_int pri
);
50 static void openpic2_set_spurious(u_int vector
);
52 /* Timer Interrupts */
53 static void openpic2_inittimer(u_int timer
, u_int pri
, u_int vector
);
54 static void openpic2_maptimer(u_int timer
, u_int cpumask
);
56 /* Interrupt Sources */
57 static void openpic2_enable_irq(u_int irq
);
58 static void openpic2_disable_irq(u_int irq
);
59 static void openpic2_initirq(u_int irq
, u_int pri
, u_int vector
, int polarity
,
61 static void openpic2_mapirq(u_int irq
, u_int cpumask
, u_int keepmask
);
64 * These functions are not used but the code is kept here
65 * for completeness and future reference.
67 static void openpic2_reset(void);
69 static void openpic2_enable_8259_pass_through(void);
70 static u_int
openpic2_get_priority(void);
71 static u_int
openpic2_get_spurious(void);
72 static void openpic2_set_sense(u_int irq
, int sense
);
76 * Description of the openpic for the higher-level irq code
78 static void openpic2_end_irq(unsigned int irq_nr
);
79 static void openpic2_ack_irq(unsigned int irq_nr
);
81 struct hw_interrupt_type open_pic2
= {
82 .typename
= " OpenPIC2 ",
83 .enable
= openpic2_enable_irq
,
84 .disable
= openpic2_disable_irq
,
85 .ack
= openpic2_ack_irq
,
86 .end
= openpic2_end_irq
,
90 * Accesses to the current processor's openpic registers
91 * On cascaded controller, this is only CPU 0
93 #define THIS_CPU Processor[0]
95 #define CHECK_THIS_CPU
98 #define check_arg_ipi(ipi) \
99 if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
100 printk("open_pic.c:%d: illegal ipi %d\n", __LINE__, ipi);
101 #define check_arg_timer(timer) \
102 if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
103 printk("open_pic.c:%d: illegal timer %d\n", __LINE__, timer);
104 #define check_arg_vec(vec) \
105 if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
106 printk("open_pic.c:%d: illegal vector %d\n", __LINE__, vec);
107 #define check_arg_pri(pri) \
108 if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
109 printk("open_pic.c:%d: illegal priority %d\n", __LINE__, pri);
111 * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
112 * data has probably been corrupted and we're going to panic or deadlock later
115 extern unsigned long* _get_SP(void);
116 #define check_arg_irq(irq) \
117 if (irq < open_pic2_irq_offset || irq >= NumSources+open_pic2_irq_offset \
118 || ISR[irq - open_pic2_irq_offset] == 0) { \
119 printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
120 /*print_backtrace(_get_SP());*/ }
121 #define check_arg_cpu(cpu) \
122 if (cpu < 0 || cpu >= NumProcessors){ \
123 printk("open_pic2.c:%d: illegal cpu %d\n", __LINE__, cpu); \
124 /*print_backtrace(_get_SP());*/ }
126 #define check_arg_ipi(ipi) do {} while (0)
127 #define check_arg_timer(timer) do {} while (0)
128 #define check_arg_vec(vec) do {} while (0)
129 #define check_arg_pri(pri) do {} while (0)
130 #define check_arg_irq(irq) do {} while (0)
131 #define check_arg_cpu(cpu) do {} while (0)
134 static u_int
openpic2_read(volatile u_int
*addr
)
142 static inline void openpic2_write(volatile u_int
*addr
, u_int val
)
147 static inline u_int
openpic2_readfield(volatile u_int
*addr
, u_int mask
)
149 u_int val
= openpic2_read(addr
);
153 inline void openpic2_writefield(volatile u_int
*addr
, u_int mask
,
156 u_int val
= openpic2_read(addr
);
157 openpic2_write(addr
, (val
& ~mask
) | (field
& mask
));
160 static inline void openpic2_clearfield(volatile u_int
*addr
, u_int mask
)
162 openpic2_writefield(addr
, mask
, 0);
165 static inline void openpic2_setfield(volatile u_int
*addr
, u_int mask
)
167 openpic2_writefield(addr
, mask
, mask
);
170 static void openpic2_safe_writefield(volatile u_int
*addr
, u_int mask
,
173 openpic2_setfield(addr
, OPENPIC_MASK
);
174 while (openpic2_read(addr
) & OPENPIC_ACTIVITY
);
175 openpic2_writefield(addr
, mask
| OPENPIC_MASK
, field
| OPENPIC_MASK
);
178 static void openpic2_reset(void)
180 openpic2_setfield(&OpenPIC2
->Global
.Global_Configuration0
,
181 OPENPIC_CONFIG_RESET
);
182 while (openpic2_readfield(&OpenPIC2
->Global
.Global_Configuration0
,
183 OPENPIC_CONFIG_RESET
))
187 void __init
openpic2_set_sources(int first_irq
, int num_irqs
, void *first_ISR
)
189 volatile OpenPIC_Source
*src
= first_ISR
;
192 last_irq
= first_irq
+ num_irqs
;
193 if (last_irq
> NumSources
)
194 NumSources
= last_irq
;
196 src
= &((struct OpenPIC
*)OpenPIC2_Addr
)->Source
[first_irq
];
197 for (i
= first_irq
; i
< last_irq
; ++i
, ++src
)
202 * The `offset' parameter defines where the interrupts handled by the
203 * OpenPIC start in the space of interrupt numbers that the kernel knows
204 * about. In other words, the OpenPIC's IRQ0 is numbered `offset' in the
205 * kernel's interrupt numbering scheme.
206 * We assume there is only one OpenPIC.
208 void __init
openpic2_init(int offset
)
214 if (!OpenPIC2_Addr
) {
215 printk("No OpenPIC2 found !\n");
218 OpenPIC2
= (volatile struct OpenPIC
*)OpenPIC2_Addr
;
220 if (ppc_md
.progress
) ppc_md
.progress("openpic: enter", 0x122);
222 t
= openpic2_read(&OpenPIC2
->Global
.Feature_Reporting0
);
223 switch (t
& OPENPIC_FEATURE_VERSION_MASK
) {
237 NumProcessors
= ((t
& OPENPIC_FEATURE_LAST_PROCESSOR_MASK
) >>
238 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT
) + 1;
240 openpic2_set_sources(0,
241 ((t
& OPENPIC_FEATURE_LAST_SOURCE_MASK
) >>
242 OPENPIC_FEATURE_LAST_SOURCE_SHIFT
) + 1,
244 printk("OpenPIC (2) Version %s (%d CPUs and %d IRQ sources) at %p\n",
245 version
, NumProcessors
, NumSources
, OpenPIC2
);
246 timerfreq
= openpic2_read(&OpenPIC2
->Global
.Timer_Frequency
);
248 printk("OpenPIC timer frequency is %d.%06d MHz\n",
249 timerfreq
/ 1000000, timerfreq
% 1000000);
251 open_pic2_irq_offset
= offset
;
253 /* Initialize timer interrupts */
254 if ( ppc_md
.progress
) ppc_md
.progress("openpic2: timer",0x3ba);
255 for (i
= 0; i
< OPENPIC_NUM_TIMERS
; i
++) {
256 /* Disabled, Priority 0 */
257 openpic2_inittimer(i
, 0, OPENPIC2_VEC_TIMER
+i
+offset
);
259 openpic2_maptimer(i
, 0);
262 /* Initialize external interrupts */
263 if (ppc_md
.progress
) ppc_md
.progress("openpic2: external",0x3bc);
265 openpic2_set_priority(0xf);
267 /* Init all external sources, including possibly the cascade. */
268 for (i
= 0; i
< NumSources
; i
++) {
274 /* the bootloader may have left it enabled (bad !) */
275 openpic2_disable_irq(i
+offset
);
277 sense
= (i
< OpenPIC_NumInitSenses
)? OpenPIC_InitSenses
[i
]: \
278 (IRQ_SENSE_LEVEL
| IRQ_POLARITY_NEGATIVE
);
280 if (sense
& IRQ_SENSE_MASK
)
281 irq_desc
[i
+offset
].status
= IRQ_LEVEL
;
283 /* Enabled, Priority 8 */
284 openpic2_initirq(i
, 8, i
+offset
, (sense
& IRQ_POLARITY_MASK
),
285 (sense
& IRQ_SENSE_MASK
));
287 openpic2_mapirq(i
, 1<<0, 0);
290 /* Init descriptors */
291 for (i
= offset
; i
< NumSources
+ offset
; i
++)
292 irq_desc
[i
].chip
= &open_pic2
;
294 /* Initialize the spurious interrupt */
295 if (ppc_md
.progress
) ppc_md
.progress("openpic2: spurious",0x3bd);
296 openpic2_set_spurious(OPENPIC2_VEC_SPURIOUS
+offset
);
298 openpic2_disable_8259_pass_through();
299 openpic2_set_priority(0);
301 if (ppc_md
.progress
) ppc_md
.progress("openpic2: exit",0x222);
305 static void openpic2_enable_8259_pass_through(void)
307 openpic2_clearfield(&OpenPIC2
->Global
.Global_Configuration0
,
308 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE
);
312 /* This can't be __init, it is used in openpic_sleep_restore_intrs */
313 static void openpic2_disable_8259_pass_through(void)
315 openpic2_setfield(&OpenPIC2
->Global
.Global_Configuration0
,
316 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE
);
320 * Find out the current interrupt
322 u_int
openpic2_irq(void)
328 vec
= openpic2_readfield(&OpenPIC2
->THIS_CPU
.Interrupt_Acknowledge
,
329 OPENPIC_VECTOR_MASK
);
333 void openpic2_eoi(void)
338 openpic2_write(&OpenPIC2
->THIS_CPU
.EOI
, 0);
339 /* Handle PCI write posting */
340 (void)openpic2_read(&OpenPIC2
->THIS_CPU
.EOI
);
344 static u_int
openpic2_get_priority(void)
349 return openpic2_readfield(&OpenPIC2
->THIS_CPU
.Current_Task_Priority
,
350 OPENPIC_CURRENT_TASK_PRIORITY_MASK
);
354 static void __init
openpic2_set_priority(u_int pri
)
360 openpic2_writefield(&OpenPIC2
->THIS_CPU
.Current_Task_Priority
,
361 OPENPIC_CURRENT_TASK_PRIORITY_MASK
, pri
);
365 * Get/set the spurious vector
368 static u_int
openpic2_get_spurious(void)
370 return openpic2_readfield(&OpenPIC2
->Global
.Spurious_Vector
,
371 OPENPIC_VECTOR_MASK
);
375 /* This can't be __init, it is used in openpic_sleep_restore_intrs */
376 static void openpic2_set_spurious(u_int vec
)
379 openpic2_writefield(&OpenPIC2
->Global
.Spurious_Vector
, OPENPIC_VECTOR_MASK
,
383 static DEFINE_SPINLOCK(openpic2_setup_lock
);
386 * Initialize a timer interrupt (and disable it)
388 * timer: OpenPIC timer number
389 * pri: interrupt source priority
390 * vec: the vector it will produce
392 static void __init
openpic2_inittimer(u_int timer
, u_int pri
, u_int vec
)
394 check_arg_timer(timer
);
397 openpic2_safe_writefield(&OpenPIC2
->Global
.Timer
[timer
].Vector_Priority
,
398 OPENPIC_PRIORITY_MASK
| OPENPIC_VECTOR_MASK
,
399 (pri
<< OPENPIC_PRIORITY_SHIFT
) | vec
);
403 * Map a timer interrupt to one or more CPUs
405 static void __init
openpic2_maptimer(u_int timer
, u_int cpumask
)
407 check_arg_timer(timer
);
408 openpic2_write(&OpenPIC2
->Global
.Timer
[timer
].Destination
,
413 * Initalize the interrupt source which will generate an NMI.
414 * This raises the interrupt's priority from 8 to 9.
416 * irq: The logical IRQ which generates an NMI.
419 openpic2_init_nmi_irq(u_int irq
)
422 openpic2_safe_writefield(&ISR
[irq
- open_pic2_irq_offset
]->Vector_Priority
,
423 OPENPIC_PRIORITY_MASK
,
424 9 << OPENPIC_PRIORITY_SHIFT
);
429 * All functions below take an offset'ed irq argument
435 * Enable/disable an external interrupt source
437 * Externally called, irq is an offseted system-wide interrupt number
439 static void openpic2_enable_irq(u_int irq
)
444 vpp
= &ISR
[irq
- open_pic2_irq_offset
]->Vector_Priority
;
445 openpic2_clearfield(vpp
, OPENPIC_MASK
);
446 /* make sure mask gets to controller before we return to user */
448 mb(); /* sync is probably useless here */
449 } while (openpic2_readfield(vpp
, OPENPIC_MASK
));
452 static void openpic2_disable_irq(u_int irq
)
458 vpp
= &ISR
[irq
- open_pic2_irq_offset
]->Vector_Priority
;
459 openpic2_setfield(vpp
, OPENPIC_MASK
);
460 /* make sure mask gets to controller before we return to user */
462 mb(); /* sync is probably useless here */
463 vp
= openpic2_readfield(vpp
, OPENPIC_MASK
| OPENPIC_ACTIVITY
);
464 } while((vp
& OPENPIC_ACTIVITY
) && !(vp
& OPENPIC_MASK
));
469 * Initialize an interrupt source (and disable it!)
471 * irq: OpenPIC interrupt number
472 * pri: interrupt source priority
473 * vec: the vector it will produce
474 * pol: polarity (1 for positive, 0 for negative)
475 * sense: 1 for level, 0 for edge
478 openpic2_initirq(u_int irq
, u_int pri
, u_int vec
, int pol
, int sense
)
480 openpic2_safe_writefield(&ISR
[irq
]->Vector_Priority
,
481 OPENPIC_PRIORITY_MASK
| OPENPIC_VECTOR_MASK
|
482 OPENPIC_SENSE_MASK
| OPENPIC_POLARITY_MASK
,
483 (pri
<< OPENPIC_PRIORITY_SHIFT
) | vec
|
484 (pol
? OPENPIC_POLARITY_POSITIVE
:
485 OPENPIC_POLARITY_NEGATIVE
) |
486 (sense
? OPENPIC_SENSE_LEVEL
: OPENPIC_SENSE_EDGE
));
490 * Map an interrupt source to one or more CPUs
492 static void openpic2_mapirq(u_int irq
, u_int physmask
, u_int keepmask
)
497 physmask
|= openpic2_read(&ISR
[irq
]->Destination
) & keepmask
;
498 openpic2_write(&ISR
[irq
]->Destination
, physmask
);
503 * Set the sense for an interrupt source (and disable it!)
505 * sense: 1 for level, 0 for edge
507 static void openpic2_set_sense(u_int irq
, int sense
)
510 openpic2_safe_writefield(&ISR
[irq
]->Vector_Priority
,
512 (sense
? OPENPIC_SENSE_LEVEL
: 0));
516 /* No spinlocks, should not be necessary with the OpenPIC
517 * (1 register = 1 interrupt and we have the desc lock).
519 static void openpic2_ack_irq(unsigned int irq_nr
)
521 openpic2_disable_irq(irq_nr
);
525 static void openpic2_end_irq(unsigned int irq_nr
)
527 if (!(irq_desc
[irq_nr
].status
& (IRQ_DISABLED
|IRQ_INPROGRESS
)))
528 openpic2_enable_irq(irq_nr
);
532 openpic2_get_irq(void)
534 int irq
= openpic2_irq();
536 if (irq
== (OPENPIC2_VEC_SPURIOUS
+ open_pic2_irq_offset
))
544 * We implement the IRQ controller as a sysdev and put it
545 * to sleep at powerdown stage (the callback is named suspend,
546 * but it's old semantics, for the Device Model, it's really
547 * powerdown). The possible problem is that another sysdev that
548 * happens to be suspend after this one will have interrupts off,
549 * that may be an issue... For now, this isn't an issue on pmac
553 static u32 save_ipi_vp
[OPENPIC_NUM_IPI
];
554 static u32 save_irq_src_vp
[OPENPIC_MAX_SOURCES
];
555 static u32 save_irq_src_dest
[OPENPIC_MAX_SOURCES
];
556 static u32 save_cpu_task_pri
[OPENPIC_MAX_PROCESSORS
];
557 static int openpic_suspend_count
;
559 static void openpic2_cached_enable_irq(u_int irq
)
562 save_irq_src_vp
[irq
- open_pic2_irq_offset
] &= ~OPENPIC_MASK
;
565 static void openpic2_cached_disable_irq(u_int irq
)
568 save_irq_src_vp
[irq
- open_pic2_irq_offset
] |= OPENPIC_MASK
;
571 /* WARNING: Can be called directly by the cpufreq code with NULL parameter,
572 * we need something better to deal with that... Maybe switch to S1 for
575 int openpic2_suspend(struct sys_device
*sysdev
, pm_message_t state
)
580 spin_lock_irqsave(&openpic2_setup_lock
, flags
);
582 if (openpic_suspend_count
++ > 0) {
583 spin_unlock_irqrestore(&openpic2_setup_lock
, flags
);
587 open_pic2
.enable
= openpic2_cached_enable_irq
;
588 open_pic2
.disable
= openpic2_cached_disable_irq
;
590 for (i
=0; i
<NumProcessors
; i
++) {
591 save_cpu_task_pri
[i
] = openpic2_read(&OpenPIC2
->Processor
[i
].Current_Task_Priority
);
592 openpic2_writefield(&OpenPIC2
->Processor
[i
].Current_Task_Priority
,
593 OPENPIC_CURRENT_TASK_PRIORITY_MASK
, 0xf);
596 for (i
=0; i
<OPENPIC_NUM_IPI
; i
++)
597 save_ipi_vp
[i
] = openpic2_read(&OpenPIC2
->Global
.IPI_Vector_Priority(i
));
598 for (i
=0; i
<NumSources
; i
++) {
601 save_irq_src_vp
[i
] = openpic2_read(&ISR
[i
]->Vector_Priority
) & ~OPENPIC_ACTIVITY
;
602 save_irq_src_dest
[i
] = openpic2_read(&ISR
[i
]->Destination
);
605 spin_unlock_irqrestore(&openpic2_setup_lock
, flags
);
610 /* WARNING: Can be called directly by the cpufreq code with NULL parameter,
611 * we need something better to deal with that... Maybe switch to S1 for
614 int openpic2_resume(struct sys_device
*sysdev
)
618 u32 vppmask
= OPENPIC_PRIORITY_MASK
| OPENPIC_VECTOR_MASK
|
619 OPENPIC_SENSE_MASK
| OPENPIC_POLARITY_MASK
|
622 spin_lock_irqsave(&openpic2_setup_lock
, flags
);
624 if ((--openpic_suspend_count
) > 0) {
625 spin_unlock_irqrestore(&openpic2_setup_lock
, flags
);
631 /* OpenPIC sometimes seem to need some time to be fully back up... */
633 openpic2_set_spurious(OPENPIC2_VEC_SPURIOUS
+open_pic2_irq_offset
);
634 } while(openpic2_readfield(&OpenPIC2
->Global
.Spurious_Vector
, OPENPIC_VECTOR_MASK
)
635 != (OPENPIC2_VEC_SPURIOUS
+ open_pic2_irq_offset
));
637 openpic2_disable_8259_pass_through();
639 for (i
=0; i
<OPENPIC_NUM_IPI
; i
++)
640 openpic2_write(&OpenPIC2
->Global
.IPI_Vector_Priority(i
),
642 for (i
=0; i
<NumSources
; i
++) {
645 openpic2_write(&ISR
[i
]->Destination
, save_irq_src_dest
[i
]);
646 openpic2_write(&ISR
[i
]->Vector_Priority
, save_irq_src_vp
[i
]);
647 /* make sure mask gets to controller before we return to user */
649 openpic2_write(&ISR
[i
]->Vector_Priority
, save_irq_src_vp
[i
]);
650 } while (openpic2_readfield(&ISR
[i
]->Vector_Priority
, vppmask
)
651 != (save_irq_src_vp
[i
] & vppmask
));
653 for (i
=0; i
<NumProcessors
; i
++)
654 openpic2_write(&OpenPIC2
->Processor
[i
].Current_Task_Priority
,
655 save_cpu_task_pri
[i
]);
657 open_pic2
.enable
= openpic2_enable_irq
;
658 open_pic2
.disable
= openpic2_disable_irq
;
660 spin_unlock_irqrestore(&openpic2_setup_lock
, flags
);
665 #endif /* CONFIG_PM */
668 static struct sysdev_class openpic2_sysclass
= {
672 static struct sys_device device_openpic2
= {
674 .cls
= &openpic2_sysclass
,
677 static struct sysdev_driver driver_openpic2
= {
679 .suspend
= &openpic2_suspend
,
680 .resume
= &openpic2_resume
,
681 #endif /* CONFIG_PM */
684 static int __init
init_openpic2_sysfs(void)
690 printk(KERN_DEBUG
"Registering openpic2 with sysfs...\n");
691 rc
= sysdev_class_register(&openpic2_sysclass
);
693 printk(KERN_ERR
"Failed registering openpic sys class\n");
696 rc
= sysdev_register(&device_openpic2
);
698 printk(KERN_ERR
"Failed registering openpic sys device\n");
701 rc
= sysdev_driver_register(&openpic2_sysclass
, &driver_openpic2
);
703 printk(KERN_ERR
"Failed registering openpic sys driver\n");
709 subsys_initcall(init_openpic2_sysfs
);