vserver 1.9.3
[linux-2.6.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 /*
38  *  Local (static) OpenPIC Operations
39  */
40
41
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);
52
53 #ifdef CONFIG_SMP
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);
58 #endif
59
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);
63
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,
68                             int is_level);
69 static void openpic_mapirq(u_int irq, u_int cpumask);
70
71 static void find_ISUs(void);
72
73 static u_int NumProcessors;
74 static u_int NumSources;
75 static int NumISUs;
76 static int open_pic_irq_offset;
77 static volatile unsigned char* chrp_int_ack_special;
78
79 OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
80
81 static void openpic_end_irq(unsigned int irq_nr);
82 static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask);
83
84 struct hw_interrupt_type open_pic = {
85         " OpenPIC  ",
86         NULL,
87         NULL,
88         openpic_enable_irq,
89         openpic_disable_irq,
90         NULL,
91         openpic_end_irq,
92         openpic_set_affinity
93 };
94
95 #ifdef CONFIG_SMP
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);
99
100 struct hw_interrupt_type open_pic_ipi = {
101         " OpenPIC  ",
102         NULL,
103         NULL,
104         openpic_enable_ipi,
105         openpic_disable_ipi,
106         NULL,
107         openpic_end_ipi,
108         NULL
109 };
110 #endif /* CONFIG_SMP */
111
112 unsigned int openpic_vec_ipi;
113 unsigned int openpic_vec_timer;
114 unsigned int openpic_vec_spurious;
115
116 /*
117  *  Accesses to the current processor's openpic registers
118  */
119 #ifdef CONFIG_SMP
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)
123 #else
124 #define THIS_CPU                Processor[hard_smp_processor_id()]
125 #define DECL_THIS_CPU
126 #define CHECK_THIS_CPU
127 #endif /* CONFIG_SMP */
128
129 #if 0
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);
142 /*
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
145  * anyway --Troy
146  */
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); \
150       dump_stack(); }
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); \
154         dump_stack(); }
155 #else
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)
162 #endif
163
164 #define GET_ISU(source) ISU[(source) >> 4][(source) & 0xf]
165
166 void __init pSeries_init_openpic(void)
167 {
168         struct device_node *np;
169         int i;
170         unsigned int *addrp;
171         unsigned char* chrp_int_ack_special = NULL;
172         unsigned char init_senses[NR_IRQS - NUM_ISA_INTERRUPTS];
173         int nmi_irq = -1;
174 #if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
175         struct device_node *kbd;
176 #endif
177
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");
182         else
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;
190         }
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;
194         of_node_put(np);
195 }
196
197 static inline u_int openpic_read(volatile u_int *addr)
198 {
199         u_int val;
200
201         val = in_le32(addr);
202         return val;
203 }
204
205 static inline void openpic_write(volatile u_int *addr, u_int val)
206 {
207         out_le32(addr, val);
208 }
209
210 static inline u_int openpic_readfield(volatile u_int *addr, u_int mask)
211 {
212         u_int val = openpic_read(addr);
213         return val & mask;
214 }
215
216 static inline void openpic_writefield(volatile u_int *addr, u_int mask,
217                                u_int field)
218 {
219         u_int val = openpic_read(addr);
220         openpic_write(addr, (val & ~mask) | (field & mask));
221 }
222
223 static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
224 {
225         openpic_writefield(addr, mask, 0);
226 }
227
228 static inline void openpic_setfield(volatile u_int *addr, u_int mask)
229 {
230         openpic_writefield(addr, mask, mask);
231 }
232
233 static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
234                                     u_int field)
235 {
236         unsigned int loops = 100000;
237
238         openpic_setfield(addr, OPENPIC_MASK);
239         while (openpic_read(addr) & OPENPIC_ACTIVITY) {
240                 if (!loops--) {
241                         printk(KERN_ERR "openpic_safe_writefield timeout\n");
242                         break;
243                 }
244         }
245         openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
246 }
247
248 #ifdef CONFIG_SMP
249
250 static int broken_ipi_registers;
251
252 static u_int openpic_read_IPI(volatile u_int* addr)
253 {
254         u_int val = 0;
255
256         if (broken_ipi_registers)
257                 /* yes this is right ... bug, feature, you decide! -- tgall */
258                 val = in_be32(addr);
259         else
260                 val = in_le32(addr);
261
262         return val;
263 }
264
265 static void openpic_test_broken_IPI(void)
266 {
267         u_int t;
268
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;
274         }
275 }
276
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)
279 {
280         u_int  val = openpic_read_IPI(addr);
281         openpic_write(addr, (val & ~mask) | (field & mask));
282 }
283
284 static inline void openpic_clearfield_IPI(volatile u_int *addr, u_int mask)
285 {
286         openpic_writefield_IPI(addr, mask, 0);
287 }
288
289 static inline void openpic_setfield_IPI(volatile u_int *addr, u_int mask)
290 {
291         openpic_writefield_IPI(addr, mask, mask);
292 }
293
294 static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int field)
295 {
296         unsigned int loops = 100000;
297
298         openpic_setfield_IPI(addr, OPENPIC_MASK);
299
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 ...
303          */
304         while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY) {
305                 if (!loops--) {
306                         printk(KERN_ERR "openpic_safe_writefield timeout\n");
307                         break;
308                 }
309         }
310
311         openpic_writefield_IPI(addr, mask, field | OPENPIC_MASK);
312 }
313 #endif /* CONFIG_SMP */
314
315 void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
316                          int programmer_switch_irq)
317 {
318         u_int t, i;
319         u_int timerfreq;
320         const char *version;
321
322         if (!OpenPIC_Addr) {
323                 printk(KERN_INFO "No OpenPIC found !\n");
324                 return;
325         }
326         OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
327
328         ppc64_boot_msg(0x20, "OpenPic Init");
329
330         t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
331         switch (t & OPENPIC_FEATURE_VERSION_MASK) {
332         case 1:
333                 version = "1.0";
334                 break;
335         case 2:
336                 version = "1.2";
337                 break;
338         case 3:
339                 version = "1.3";
340                 break;
341         default:
342                 version = "?";
343                 break;
344         }
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);
352         if (timerfreq)
353                 printk(KERN_INFO "OpenPIC timer frequency is %d.%06d MHz\n",
354                        timerfreq / 1000000, timerfreq % 1000000);
355
356         if (!main_pic)
357                 return;
358
359         open_pic_irq_offset = offset;
360         chrp_int_ack_special = (volatile unsigned char*)chrp_ack;
361
362         find_ISUs();
363
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);
368                 /* No processor */
369                 openpic_maptimer(i, 0);
370         }
371
372 #ifdef CONFIG_SMP
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;
381         }
382 #endif
383
384         /* Initialize external interrupts */
385         openpic_set_priority(0xf);
386
387         /* SIOint (8259 cascade) is special */
388         if (offset) {
389                 openpic_initirq(0, 8, offset, 1, 1);
390                 openpic_mapirq(0, 1 << get_hard_smp_processor_id(boot_cpuid));
391         }
392
393         /* Init all external sources */
394         for (i = 0; i < NumSources; i++) {
395                 int pri, sense;
396
397                 /* skip cascade if any */
398                 if (offset && i == 0)
399                         continue;
400                 /* the bootloader may have left it enabled (bad !) */
401                 openpic_disable_irq(i+offset);
402
403                 pri = (i == programmer_switch_irq)? 9: 8;
404                 sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
405                 if (sense)
406                         irq_desc[i+offset].status = IRQ_LEVEL;
407
408                 /* Enabled, Priority 8 or 9 */
409                 openpic_initirq(i, pri, i+offset, !sense, sense);
410                 /* Processor 0 */
411                 openpic_mapirq(i, 1 << get_hard_smp_processor_id(boot_cpuid));
412         }
413
414         /* Init descriptors */
415         for (i = offset; i < NumSources + offset; i++)
416                 irq_desc[i].handler = &open_pic;
417
418         /* Initialize the spurious interrupt */
419         openpic_set_spurious(openpic_vec_spurious);
420
421         openpic_set_priority(0);
422         openpic_disable_8259_pass_through();
423
424         ppc64_boot_msg(0x25, "OpenPic Done");
425 }
426
427 /* 
428  * We cant do this in init_IRQ because we need the memory subsystem up for
429  * request_irq()
430  */
431 static int __init openpic_setup_i8259(void)
432 {
433         if (systemcfg->platform == PLATFORM_POWERMAC)
434                 return 0;
435
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");
441                 i8259_init();
442         }
443
444         return 0;
445 }
446 arch_initcall(openpic_setup_i8259);
447
448 void openpic_setup_ISU(int isu_num, unsigned long addr)
449 {
450         if (isu_num >= OPENPIC_MAX_ISU)
451                 return;
452         ISU[isu_num] = (OpenPIC_SourcePtr) __ioremap(addr, 0x400, _PAGE_NO_CACHE);
453         if (isu_num >= NumISUs)
454                 NumISUs = isu_num + 1;
455 }
456
457 void find_ISUs(void)
458 {
459         /* For PowerMac, setup ISUs on base openpic */
460         if (systemcfg->platform == PLATFORM_POWERMAC) {
461                 int i;
462                 for (i=0; i<128; i+=0x10) {
463                         ISU[i>>4] = &((struct OpenPIC *)OpenPIC_Addr)->Source[i];
464                         NumISUs++;
465                 }
466         }
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
470          * as a result
471          * -- tgall
472          */
473
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
477          *
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.
481          */
482         if (systemcfg->platform == PLATFORM_POWERMAC) {
483                 openpic_vec_ipi = NumSources;
484                 openpic_vec_timer = openpic_vec_ipi + 4; 
485                 openpic_vec_spurious = 0xff;
486         } else {
487                 NumSources = NumISUs * 0x10;
488
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;
492         }
493 }
494
495 static inline void openpic_reset(void)
496 {
497         openpic_setfield(&OpenPIC->Global.Global_Configuration0,
498                          OPENPIC_CONFIG_RESET);
499 }
500
501 static inline void openpic_enable_8259_pass_through(void)
502 {
503         openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
504                            OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
505 }
506
507 static void openpic_disable_8259_pass_through(void)
508 {
509         openpic_setfield(&OpenPIC->Global.Global_Configuration0,
510                          OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
511 }
512
513 /*
514  *  Find out the current interrupt
515  */
516 static u_int openpic_irq(void)
517 {
518         u_int vec;
519         DECL_THIS_CPU;
520
521         CHECK_THIS_CPU;
522         vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
523                                 OPENPIC_VECTOR_MASK);
524         return vec;
525 }
526
527 static void openpic_eoi(void)
528 {
529         DECL_THIS_CPU;
530
531         CHECK_THIS_CPU;
532         openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
533         /* Handle PCI write posting */
534         (void)openpic_read(&OpenPIC->THIS_CPU.EOI);
535 }
536
537
538 static inline u_int openpic_get_priority(void)
539 {
540         DECL_THIS_CPU;
541
542         CHECK_THIS_CPU;
543         return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
544                                  OPENPIC_CURRENT_TASK_PRIORITY_MASK);
545 }
546
547 static void openpic_set_priority(u_int pri)
548 {
549         DECL_THIS_CPU;
550
551         CHECK_THIS_CPU;
552         check_arg_pri(pri);
553         openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
554                            OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
555 }
556
557 /*
558  *  Get/set the spurious vector
559  */
560 static inline u_int openpic_get_spurious(void)
561 {
562         return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
563                                  OPENPIC_VECTOR_MASK);
564 }
565
566 static void openpic_set_spurious(u_int vec)
567 {
568         check_arg_vec(vec);
569         openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
570                            vec);
571 }
572
573 /*
574  * Convert a cpu mask from logical to physical cpu numbers.
575  */
576 static inline u32 physmask(u32 cpumask)
577 {
578         int i;
579         u32 mask = 0;
580
581         for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1)
582                 mask |= (cpumask & 1) << get_hard_smp_processor_id(i);
583         return mask;
584 }
585
586 void openpic_init_processor(u_int cpumask)
587 {
588         openpic_write(&OpenPIC->Global.Processor_Initialization,
589                       physmask(cpumask & cpus_addr(cpu_online_map)[0]));
590 }
591
592 #ifdef CONFIG_SMP
593 /*
594  *  Initialize an interprocessor interrupt (and disable it)
595  *
596  *  ipi: OpenPIC interprocessor interrupt number
597  *  pri: interrupt source priority
598  *  vec: the vector it will produce
599  */
600 static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec)
601 {
602         check_arg_ipi(ipi);
603         check_arg_pri(pri);
604         check_arg_vec(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);
608 }
609
610 /*
611  *  Send an IPI to one or more CPUs
612  *  
613  *  Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
614  *  and not a system-wide interrupt number
615  */
616 void openpic_cause_IPI(u_int ipi, u_int cpumask)
617 {
618         DECL_THIS_CPU;
619
620         CHECK_THIS_CPU;
621         check_arg_ipi(ipi);
622         openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
623                       physmask(cpumask & cpus_addr(cpu_online_map)[0]));
624 }
625
626 void openpic_request_IPIs(void)
627 {
628         int i;
629         
630         /*
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 */
634         
635         if (OpenPIC == NULL)
636                 return;
637
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);
647
648         for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
649                 openpic_enable_ipi(openpic_vec_ipi+i);
650 }
651
652 /*
653  * Do per-cpu setup for SMP systems.
654  *
655  * Get IPI's working and start taking interrupts.
656  *   -- Cort
657  */
658 static spinlock_t openpic_setup_lock __devinitdata = SPIN_LOCK_UNLOCKED;
659
660 void __devinit do_openpic_setup_cpu(void)
661 {
662 #ifdef CONFIG_IRQ_ALL_CPUS
663         int i;
664         u32 msk = 1 << hard_smp_processor_id();
665 #endif
666
667         spin_lock(&openpic_setup_lock);
668
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
674          * in irq.c.
675          */
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);
680
681         spin_unlock(&openpic_setup_lock);
682 }
683 #endif /* CONFIG_SMP */
684
685 /*
686  *  Initialize a timer interrupt (and disable it)
687  *
688  *  timer: OpenPIC timer number
689  *  pri: interrupt source priority
690  *  vec: the vector it will produce
691  */
692 static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec)
693 {
694         check_arg_timer(timer);
695         check_arg_pri(pri);
696         check_arg_vec(vec);
697         openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
698                                 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
699                                 (pri << OPENPIC_PRIORITY_SHIFT) | vec);
700 }
701
702 /*
703  *  Map a timer interrupt to one or more CPUs
704  */
705 static void __init openpic_maptimer(u_int timer, u_int cpumask)
706 {
707         check_arg_timer(timer);
708         openpic_write(&OpenPIC->Global.Timer[timer].Destination,
709                       physmask(cpumask & cpus_addr(cpu_online_map)[0]));
710 }
711
712
713 /*
714  *
715  * All functions below take an offset'ed irq argument
716  *
717  */
718
719
720 /*
721  *  Enable/disable an external interrupt source
722  *
723  *  Externally called, irq is an offseted system-wide interrupt number
724  */
725 static void openpic_enable_irq(u_int irq)
726 {
727         unsigned int loops = 100000;
728         check_arg_irq(irq);
729
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 */
732         do {
733                 if (!loops--) {
734                         printk(KERN_ERR "openpic_enable_irq timeout\n");
735                         break;
736                 }
737
738                 mb(); /* sync is probably useless here */
739         } while(openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
740                         OPENPIC_MASK));
741 }
742
743 static void openpic_disable_irq(u_int irq)
744 {
745         u32 vp;
746         unsigned int loops = 100000;
747         
748         check_arg_irq(irq);
749
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 */
752         do {
753                 if (!loops--) {
754                         printk(KERN_ERR "openpic_disable_irq timeout\n");
755                         break;
756                 }
757
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));
762 }
763
764 #ifdef CONFIG_SMP
765 /*
766  *  Enable/disable an IPI interrupt source
767  *  
768  *  Externally called, irq is an offseted system-wide interrupt number
769  */
770 void openpic_enable_ipi(u_int irq)
771 {
772         irq -= openpic_vec_ipi;
773         check_arg_ipi(irq);
774         openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
775
776 }
777 void openpic_disable_ipi(u_int irq)
778 {
779    /* NEVER disable an IPI... that's just plain wrong! */
780 }
781
782 #endif
783
784 /*
785  *  Initialize an interrupt source (and disable it!)
786  *
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
792  */
793 static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
794 {
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));
802 }
803
804 /*
805  *  Map an interrupt source to one or more CPUs
806  */
807 static void openpic_mapirq(u_int irq, u_int physmask)
808 {
809         openpic_write(&GET_ISU(irq).Destination, physmask);
810 }
811
812 /*
813  *  Set the sense for an interrupt source (and disable it!)
814  *
815  *  sense: 1 for level, 0 for edge
816  */
817 #if 0   /* not used */
818 static void openpic_set_sense(u_int irq, int sense)
819 {
820         openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
821                                 OPENPIC_SENSE_LEVEL,
822                                 (sense ? OPENPIC_SENSE_LEVEL : 0));
823 }
824
825 static int openpic_get_sense(u_int irq)
826 {
827         return openpic_readfield(&GET_ISU(irq).Vector_Priority,
828                                  OPENPIC_SENSE_LEVEL) != 0;
829 }
830 #endif
831
832 static void openpic_end_irq(unsigned int irq_nr)
833 {
834         openpic_eoi();
835 }
836
837 static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask)
838 {
839         cpumask_t tmp;
840
841         cpus_and(tmp, cpumask, cpu_online_map);
842         openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpus_addr(tmp)[0]));
843 }
844
845 #ifdef CONFIG_SMP
846 static void openpic_end_ipi(unsigned int irq_nr)
847 {
848         /*
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
853          * irqs disabled.
854          */
855         openpic_eoi();
856 }
857
858 static irqreturn_t openpic_ipi_action(int cpl, void *dev_id,
859                                         struct pt_regs *regs)
860 {
861         smp_message_recv(cpl-openpic_vec_ipi, regs);
862         return IRQ_HANDLED;
863 }
864
865 #endif /* CONFIG_SMP */
866
867 int openpic_get_irq(struct pt_regs *regs)
868 {
869         extern int i8259_irq(int cpu);
870
871         int irq = openpic_irq();
872
873         if (open_pic_irq_offset && irq == open_pic_irq_offset) {
874                 /*
875                  * This magic address generates a PCI IACK cycle.
876                  */
877                 if ( chrp_int_ack_special )
878                         irq = *chrp_int_ack_special;
879                 else
880                         irq = i8259_irq( smp_processor_id() );
881                 openpic_eoi();
882         }
883         if (irq == openpic_vec_spurious)
884                 irq = -1;
885         return irq;
886 }