commented early_printk patch because of rejects.
[linux-flexiantxendom0-3.2.10.git] / arch / ppc64 / kernel / open_pic.c
1 /*
2  *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
3  *
4  *  Copyright (C) 1997 Geert Uytterhoeven
5  *
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
8  *  for more details.
9  */
10
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>
20 #include <asm/io.h>
21 #include <asm/pgtable.h>
22 #include <asm/irq.h>
23 #include <asm/prom.h>
24
25 #include <asm/machdep.h>
26
27 #include "open_pic.h"
28 #include "open_pic_defs.h"
29 #include "i8259.h"
30 #include <asm/ppcdebug.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
37 void find_ISUs(void);
38
39 static u_int NumProcessors;
40 static u_int NumSources;
41 static int NumISUs;
42 static int open_pic_irq_offset;
43 static volatile unsigned char* chrp_int_ack_special;
44 static int broken_ipi_registers;
45
46 OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
47
48 static void openpic_end_irq(unsigned int irq_nr);
49 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
50
51 struct hw_interrupt_type open_pic = {
52         " OpenPIC  ",
53         NULL,
54         NULL,
55         openpic_enable_irq,
56         openpic_disable_irq,
57         NULL,
58         openpic_end_irq,
59         openpic_set_affinity
60 };
61
62 #ifdef CONFIG_SMP
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);
66
67 struct hw_interrupt_type open_pic_ipi = {
68         " OpenPIC  ",
69         NULL,
70         NULL,
71         openpic_enable_ipi,
72         openpic_disable_ipi,
73         NULL,
74         openpic_end_ipi,
75         NULL
76 };
77 #endif /* CONFIG_SMP */
78
79 unsigned int openpic_vec_ipi;
80 unsigned int openpic_vec_timer;
81 unsigned int openpic_vec_spurious;
82
83 /*
84  *  Accesses to the current processor's openpic registers
85  */
86 #ifdef CONFIG_SMP
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)
90 #else
91 #define THIS_CPU                Processor[smp_processor_id()]
92 #define DECL_THIS_CPU
93 #define CHECK_THIS_CPU
94 #endif /* CONFIG_SMP */
95
96 #if 0
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);
109 /*
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
112  * anyway --Troy
113  */
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); \
117       dump_stack(); }
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); \
121         dump_stack(); }
122 #else
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)
129 #endif
130
131 #define GET_ISU(source) ISU[(source) >> 4][(source) & 0xf]
132
133 void __init openpic_init_IRQ(void)
134 {
135         struct device_node *np;
136         int i;
137         unsigned int *addrp;
138         unsigned char* chrp_int_ack_special = 0;
139         unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
140         int nmi_irq = -1;
141 #if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
142         struct device_node *kbd;
143 #endif
144
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");
149         else
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;
157         }
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;
161 }
162
163 static inline u_int openpic_read(volatile u_int *addr)
164 {
165         u_int val;
166
167         val = in_le32(addr);
168         return val;
169 }
170
171 static inline void openpic_write(volatile u_int *addr, u_int val)
172 {
173         out_le32(addr, val);
174 }
175
176 static inline u_int openpic_readfield(volatile u_int *addr, u_int mask)
177 {
178         u_int val = openpic_read(addr);
179         return val & mask;
180 }
181
182 static inline void openpic_writefield(volatile u_int *addr, u_int mask,
183                                u_int field)
184 {
185         u_int val = openpic_read(addr);
186         openpic_write(addr, (val & ~mask) | (field & mask));
187 }
188
189 static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
190 {
191         openpic_writefield(addr, mask, 0);
192 }
193
194 static inline void openpic_setfield(volatile u_int *addr, u_int mask)
195 {
196         openpic_writefield(addr, mask, mask);
197 }
198
199 static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
200                                     u_int field)
201 {
202         unsigned int loops = 100000;
203
204         openpic_setfield(addr, OPENPIC_MASK);
205         while (openpic_read(addr) & OPENPIC_ACTIVITY) {
206                 if (!loops--) {
207                         printk(KERN_ERR "openpic_safe_writefield timeout\n");
208                         break;
209                 }
210         }
211         openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
212 }
213
214 #ifdef CONFIG_SMP
215 static u_int openpic_read_IPI(volatile u_int* addr)
216 {
217         u_int val = 0;
218
219         if (broken_ipi_registers)
220                 /* yes this is right ... bug, feature, you decide! -- tgall */
221                 val = in_be32(addr);
222         else
223                 val = in_le32(addr);
224
225         return val;
226 }
227
228 static void openpic_test_broken_IPI(void)
229 {
230         u_int t;
231
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;
237         }
238 }
239
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)
242 {
243         u_int  val = openpic_read_IPI(addr);
244         openpic_write(addr, (val & ~mask) | (field & mask));
245 }
246
247 static inline void openpic_clearfield_IPI(volatile u_int *addr, u_int mask)
248 {
249         openpic_writefield_IPI(addr, mask, 0);
250 }
251
252 static inline void openpic_setfield_IPI(volatile u_int *addr, u_int mask)
253 {
254         openpic_writefield_IPI(addr, mask, mask);
255 }
256
257 static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int field)
258 {
259         unsigned int loops = 100000;
260
261         openpic_setfield_IPI(addr, OPENPIC_MASK);
262
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 ...
266          */
267         while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY) {
268                 if (!loops--) {
269                         printk(KERN_ERR "openpic_safe_writefield timeout\n");
270                         break;
271                 }
272         }
273
274         openpic_writefield_IPI(addr, mask, field | OPENPIC_MASK);
275 }
276 #endif /* CONFIG_SMP */
277
278 void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
279                          int programmer_switch_irq)
280 {
281         u_int t, i;
282         u_int timerfreq;
283         const char *version;
284
285         if (!OpenPIC_Addr) {
286                 printk(KERN_INFO "No OpenPIC found !\n");
287                 return;
288         }
289         OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
290
291         ppc64_boot_msg(0x20, "OpenPic Init");
292
293         t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
294         switch (t & OPENPIC_FEATURE_VERSION_MASK) {
295         case 1:
296                 version = "1.0";
297                 break;
298         case 2:
299                 version = "1.2";
300                 break;
301         case 3:
302                 version = "1.3";
303                 break;
304         default:
305                 version = "?";
306                 break;
307         }
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);
315         if (timerfreq)
316                 printk(KERN_INFO "OpenPIC timer frequency is %d.%06d MHz\n",
317                        timerfreq / 1000000, timerfreq % 1000000);
318
319         if (!main_pic)
320                 return;
321
322         open_pic_irq_offset = offset;
323         chrp_int_ack_special = (volatile unsigned char*)chrp_ack;
324
325         find_ISUs();
326
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);
332                 /* No processor */
333                 openpic_maptimer(i, 0);
334         }
335
336 #ifdef CONFIG_SMP
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;
346         }
347 #endif
348
349         /* Initialize external interrupts */
350         ppc64_boot_msg(0x23, "OpenPic Ext");
351
352         openpic_set_priority(0xf);
353
354         /* SIOint (8259 cascade) is special */
355         if (offset) {
356                 openpic_initirq(0, 8, offset, 1, 1);
357                 openpic_mapirq(0, 1 << boot_cpuid);
358         }
359
360         /* Init all external sources */
361         for (i = 1; i < NumSources; i++) {
362                 int pri, sense;
363
364                 /* the bootloader may have left it enabled (bad !) */
365                 openpic_disable_irq(i+offset);
366
367                 pri = (i == programmer_switch_irq)? 9: 8;
368                 sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
369                 if (sense)
370                         irq_desc[i+offset].status = IRQ_LEVEL;
371
372                 /* Enabled, Priority 8 or 9 */
373                 openpic_initirq(i, pri, i+offset, !sense, sense);
374                 /* Processor 0 */
375                 openpic_mapirq(i, 1 << boot_cpuid);
376         }
377
378         /* Init descriptors */
379         for (i = offset; i < NumSources + offset; i++)
380                 irq_desc[i].handler = &open_pic;
381
382         /* Initialize the spurious interrupt */
383         ppc64_boot_msg(0x24, "OpenPic Spurious");
384         openpic_set_spurious(openpic_vec_spurious);
385
386         openpic_set_priority(0);
387         openpic_disable_8259_pass_through();
388
389         ppc64_boot_msg(0x25, "OpenPic Done");
390 }
391
392 /* 
393  * We cant do this in init_IRQ because we need the memory subsystem up for
394  * request_irq()
395  */
396 static int __init openpic_setup_i8259(void)
397 {
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");
403                 i8259_init();
404         }
405
406         return 0;
407 }
408 arch_initcall(openpic_setup_i8259);
409
410 void openpic_setup_ISU(int isu_num, unsigned long addr)
411 {
412         if (isu_num >= OPENPIC_MAX_ISU)
413                 return;
414         ISU[isu_num] = (OpenPIC_SourcePtr) __ioremap(addr, 0x400, _PAGE_NO_CACHE);
415         if (isu_num >= NumISUs)
416                 NumISUs = isu_num + 1;
417 }
418
419 void find_ISUs(void)
420 {
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
424          * as a result
425          * -- tgall
426          */
427
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
431          */
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;
436 }
437
438 static inline void openpic_reset(void)
439 {
440         openpic_setfield(&OpenPIC->Global.Global_Configuration0,
441                          OPENPIC_CONFIG_RESET);
442 }
443
444 static inline void openpic_enable_8259_pass_through(void)
445 {
446         openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
447                            OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
448 }
449
450 static void openpic_disable_8259_pass_through(void)
451 {
452         openpic_setfield(&OpenPIC->Global.Global_Configuration0,
453                          OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
454 }
455
456 /*
457  *  Find out the current interrupt
458  */
459 static u_int openpic_irq(void)
460 {
461         u_int vec;
462         DECL_THIS_CPU;
463
464         CHECK_THIS_CPU;
465         vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
466                                 OPENPIC_VECTOR_MASK);
467         return vec;
468 }
469
470 static void openpic_eoi(void)
471 {
472         DECL_THIS_CPU;
473
474         CHECK_THIS_CPU;
475         openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
476         /* Handle PCI write posting */
477         (void)openpic_read(&OpenPIC->THIS_CPU.EOI);
478 }
479
480
481 static inline u_int openpic_get_priority(void)
482 {
483         DECL_THIS_CPU;
484
485         CHECK_THIS_CPU;
486         return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
487                                  OPENPIC_CURRENT_TASK_PRIORITY_MASK);
488 }
489
490 static void openpic_set_priority(u_int pri)
491 {
492         DECL_THIS_CPU;
493
494         CHECK_THIS_CPU;
495         check_arg_pri(pri);
496         openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
497                            OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
498 }
499
500 /*
501  *  Get/set the spurious vector
502  */
503 static inline u_int openpic_get_spurious(void)
504 {
505         return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
506                                  OPENPIC_VECTOR_MASK);
507 }
508
509 static void openpic_set_spurious(u_int vec)
510 {
511         check_arg_vec(vec);
512         openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
513                            vec);
514 }
515
516 void openpic_init_processor(u_int cpumask)
517 {
518         openpic_write(&OpenPIC->Global.Processor_Initialization,
519                       cpumask & cpu_online_map);
520 }
521
522 #ifdef CONFIG_SMP
523 /*
524  *  Initialize an interprocessor interrupt (and disable it)
525  *
526  *  ipi: OpenPIC interprocessor interrupt number
527  *  pri: interrupt source priority
528  *  vec: the vector it will produce
529  */
530 static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec)
531 {
532         check_arg_ipi(ipi);
533         check_arg_pri(pri);
534         check_arg_vec(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);
538 }
539
540 /*
541  *  Send an IPI to one or more CPUs
542  *  
543  *  Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
544  *  and not a system-wide interrupt number
545  */
546 void openpic_cause_IPI(u_int ipi, u_int cpumask)
547 {
548         DECL_THIS_CPU;
549
550         CHECK_THIS_CPU;
551         check_arg_ipi(ipi);
552         openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
553                       cpumask & cpu_online_map);
554 }
555
556 void openpic_request_IPIs(void)
557 {
558         int i;
559         
560         /*
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 */
564         
565         if (OpenPIC == NULL)
566                 return;
567
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);
577
578         for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
579                 openpic_enable_ipi(openpic_vec_ipi+i);
580 }
581
582 /*
583  * Do per-cpu setup for SMP systems.
584  *
585  * Get IPI's working and start taking interrupts.
586  *   -- Cort
587  */
588 static spinlock_t openpic_setup_lock __devinitdata = SPIN_LOCK_UNLOCKED;
589
590 void __devinit do_openpic_setup_cpu(void)
591 {
592 #ifdef CONFIG_IRQ_ALL_CPUS
593         int i;
594         u32 msk = 1 << smp_processor_id();
595 #endif
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                       cpumask & cpu_online_map);
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         unsigned int loops = 100000;
658         check_arg_irq(irq);
659
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 */
662         do {
663                 if (!loops--) {
664                         printk(KERN_ERR "openpic_enable_irq timeout\n");
665                         break;
666                 }
667
668                 mb(); /* sync is probably useless here */
669         } while(openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
670                         OPENPIC_MASK));
671 }
672
673 static void openpic_disable_irq(u_int irq)
674 {
675         u32 vp;
676         unsigned int loops = 100000;
677         
678         check_arg_irq(irq);
679
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 */
682         do {
683                 if (!loops--) {
684                         printk(KERN_ERR "openpic_disable_irq timeout\n");
685                         break;
686                 }
687
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));
692 }
693
694 #ifdef CONFIG_SMP
695 /*
696  *  Enable/disable an IPI interrupt source
697  *  
698  *  Externally called, irq is an offseted system-wide interrupt number
699  */
700 void openpic_enable_ipi(u_int irq)
701 {
702         irq -= openpic_vec_ipi;
703         check_arg_ipi(irq);
704         openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
705
706 }
707 void openpic_disable_ipi(u_int irq)
708 {
709    /* NEVER disable an IPI... that's just plain wrong! */
710 }
711
712 #endif
713
714 /*
715  *  Initialize an interrupt source (and disable it!)
716  *
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
722  */
723 static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
724 {
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));
732 }
733
734 /*
735  *  Map an interrupt source to one or more CPUs
736  */
737 static void openpic_mapirq(u_int irq, u_int physmask)
738 {
739         openpic_write(&GET_ISU(irq).Destination, physmask);
740 }
741
742 /*
743  *  Set the sense for an interrupt source (and disable it!)
744  *
745  *  sense: 1 for level, 0 for edge
746  */
747 static inline void openpic_set_sense(u_int irq, int sense)
748 {
749         openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
750                                 OPENPIC_SENSE_LEVEL,
751                                 (sense ? OPENPIC_SENSE_LEVEL : 0));
752 }
753
754 static void openpic_end_irq(unsigned int irq_nr)
755 {
756         if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
757                 openpic_eoi();
758 }
759
760 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
761 {
762         openpic_mapirq(irq_nr - open_pic_irq_offset, cpumask & cpu_online_map);
763 }
764
765 #ifdef CONFIG_SMP
766 static void openpic_end_ipi(unsigned int irq_nr)
767 {
768         /*
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
773          * irqs disabled.
774          */
775         openpic_eoi();
776 }
777
778 static irqreturn_t openpic_ipi_action(int cpl, void *dev_id,
779                                         struct pt_regs *regs)
780 {
781         smp_message_recv(cpl-openpic_vec_ipi, regs);
782         return IRQ_HANDLED;
783 }
784
785 #endif /* CONFIG_SMP */
786
787 int openpic_get_irq(struct pt_regs *regs)
788 {
789         extern int i8259_irq(int cpu);
790
791         int irq = openpic_irq();
792
793         /* Management of the cascade should be moved out of here */
794         if (open_pic_irq_offset && irq == open_pic_irq_offset)
795         {
796                 /*
797                  * This magic address generates a PCI IACK cycle.
798                  */
799                 if ( chrp_int_ack_special )
800                         irq = *chrp_int_ack_special;
801                 else
802                         irq = i8259_irq( smp_processor_id() );
803                 openpic_eoi();
804         }
805         if (irq == openpic_vec_spurious)
806                 irq = -1;
807         return irq;
808 }