Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / arch / ppc / syslib / 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/sched.h>
15 #include <linux/init.h>
16 #include <linux/irq.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>
22 #include <asm/io.h>
23 #include <asm/irq.h>
24 #include <asm/prom.h>
25 #include <asm/sections.h>
26 #include <asm/open_pic.h>
27 #include <asm/i8259.h>
28
29 #include "open_pic_defs.h"
30
31 #if defined(CONFIG_PRPMC800) || defined(CONFIG_85xx)
32 #define OPENPIC_BIG_ENDIAN
33 #endif
34
35 void __iomem *OpenPIC_Addr;
36 static volatile struct OpenPIC __iomem *OpenPIC = NULL;
37
38 /*
39  * We define OpenPIC_InitSenses table thusly:
40  * bit 0x1: sense, 0 for edge and 1 for level.
41  * bit 0x2: polarity, 0 for negative, 1 for positive.
42  */
43 u_int OpenPIC_NumInitSenses __initdata = 0;
44 u_char *OpenPIC_InitSenses __initdata = NULL;
45 extern int use_of_interrupt_tree;
46
47 static u_int NumProcessors;
48 static u_int NumSources;
49 static int open_pic_irq_offset;
50 static volatile OpenPIC_Source __iomem *ISR[NR_IRQS];
51 static int openpic_cascade_irq = -1;
52 static int (*openpic_cascade_fn)(struct pt_regs *);
53
54 /* Global Operations */
55 static void openpic_disable_8259_pass_through(void);
56 static void openpic_set_spurious(u_int vector);
57
58 #ifdef CONFIG_SMP
59 /* Interprocessor Interrupts */
60 static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
61 static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *);
62 #endif
63
64 /* Timer Interrupts */
65 static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
66 static void openpic_maptimer(u_int timer, cpumask_t cpumask);
67
68 /* Interrupt Sources */
69 static void openpic_enable_irq(u_int irq);
70 static void openpic_disable_irq(u_int irq);
71 static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
72                             int is_level);
73 static void openpic_mapirq(u_int irq, cpumask_t cpumask, cpumask_t keepmask);
74
75 /*
76  * These functions are not used but the code is kept here
77  * for completeness and future reference.
78  */
79 #ifdef notused
80 static void openpic_enable_8259_pass_through(void);
81 static u_int openpic_get_priority(void);
82 static u_int openpic_get_spurious(void);
83 static void openpic_set_sense(u_int irq, int sense);
84 #endif /* notused */
85
86 /*
87  * Description of the openpic for the higher-level irq code
88  */
89 static void openpic_end_irq(unsigned int irq_nr);
90 static void openpic_ack_irq(unsigned int irq_nr);
91 static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask);
92
93 struct hw_interrupt_type open_pic = {
94         .typename       = " OpenPIC  ",
95         .enable         = openpic_enable_irq,
96         .disable        = openpic_disable_irq,
97         .ack            = openpic_ack_irq,
98         .end            = openpic_end_irq,
99         .set_affinity   = openpic_set_affinity,
100 };
101
102 #ifdef CONFIG_SMP
103 static void openpic_end_ipi(unsigned int irq_nr);
104 static void openpic_ack_ipi(unsigned int irq_nr);
105 static void openpic_enable_ipi(unsigned int irq_nr);
106 static void openpic_disable_ipi(unsigned int irq_nr);
107
108 struct hw_interrupt_type open_pic_ipi = {
109         .typename       = " OpenPIC  ",
110         .enable         = openpic_enable_ipi,
111         .disable        = openpic_disable_ipi,
112         .ack            = openpic_ack_ipi,
113         .end            = openpic_end_ipi,
114 };
115 #endif /* CONFIG_SMP */
116
117 /*
118  *  Accesses to the current processor's openpic registers
119  */
120 #ifdef CONFIG_SMP
121 #define THIS_CPU                Processor[cpu]
122 #define DECL_THIS_CPU           int cpu = smp_hw_index[smp_processor_id()]
123 #define CHECK_THIS_CPU          check_arg_cpu(cpu)
124 #else
125 #define THIS_CPU                Processor[0]
126 #define DECL_THIS_CPU
127 #define CHECK_THIS_CPU
128 #endif /* CONFIG_SMP */
129
130 #if 1
131 #define check_arg_ipi(ipi) \
132     if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
133         printk("open_pic.c:%d: invalid ipi %d\n", __LINE__, ipi);
134 #define check_arg_timer(timer) \
135     if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
136         printk("open_pic.c:%d: invalid timer %d\n", __LINE__, timer);
137 #define check_arg_vec(vec) \
138     if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
139         printk("open_pic.c:%d: invalid vector %d\n", __LINE__, vec);
140 #define check_arg_pri(pri) \
141     if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
142         printk("open_pic.c:%d: invalid priority %d\n", __LINE__, pri);
143 /*
144  * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
145  * data has probably been corrupted and we're going to panic or deadlock later
146  * anyway --Troy
147  */
148 #define check_arg_irq(irq) \
149     if (irq < open_pic_irq_offset || irq >= NumSources+open_pic_irq_offset \
150         || ISR[irq - open_pic_irq_offset] == 0) { \
151       printk("open_pic.c:%d: invalid irq %d\n", __LINE__, irq); \
152       dump_stack(); }
153 #define check_arg_cpu(cpu) \
154     if (cpu < 0 || cpu >= NumProcessors){ \
155         printk("open_pic.c:%d: invalid cpu %d\n", __LINE__, cpu); \
156         dump_stack(); }
157 #else
158 #define check_arg_ipi(ipi)      do {} while (0)
159 #define check_arg_timer(timer)  do {} while (0)
160 #define check_arg_vec(vec)      do {} while (0)
161 #define check_arg_pri(pri)      do {} while (0)
162 #define check_arg_irq(irq)      do {} while (0)
163 #define check_arg_cpu(cpu)      do {} while (0)
164 #endif
165
166 u_int openpic_read(volatile u_int __iomem *addr)
167 {
168         u_int val;
169
170 #ifdef OPENPIC_BIG_ENDIAN
171         val = in_be32(addr);
172 #else
173         val = in_le32(addr);
174 #endif
175         return val;
176 }
177
178 static inline void openpic_write(volatile u_int __iomem *addr, u_int val)
179 {
180 #ifdef OPENPIC_BIG_ENDIAN
181         out_be32(addr, val);
182 #else
183         out_le32(addr, val);
184 #endif
185 }
186
187 static inline u_int openpic_readfield(volatile u_int __iomem *addr, u_int mask)
188 {
189         u_int val = openpic_read(addr);
190         return val & mask;
191 }
192
193 inline void openpic_writefield(volatile u_int __iomem *addr, u_int mask,
194                                u_int field)
195 {
196         u_int val = openpic_read(addr);
197         openpic_write(addr, (val & ~mask) | (field & mask));
198 }
199
200 static inline void openpic_clearfield(volatile u_int __iomem *addr, u_int mask)
201 {
202         openpic_writefield(addr, mask, 0);
203 }
204
205 static inline void openpic_setfield(volatile u_int __iomem *addr, u_int mask)
206 {
207         openpic_writefield(addr, mask, mask);
208 }
209
210 static void openpic_safe_writefield(volatile u_int __iomem *addr, u_int mask,
211                                     u_int field)
212 {
213         openpic_setfield(addr, OPENPIC_MASK);
214         while (openpic_read(addr) & OPENPIC_ACTIVITY);
215         openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
216 }
217
218 #ifdef CONFIG_SMP
219 /* yes this is right ... bug, feature, you decide! -- tgall */
220 u_int openpic_read_IPI(volatile u_int __iomem * addr)
221 {
222          u_int val = 0;
223 #if defined(OPENPIC_BIG_ENDIAN) || defined(CONFIG_POWER3)
224         val = in_be32(addr);
225 #else
226         val = in_le32(addr);
227 #endif
228         return val;
229 }
230
231 /* because of the power3 be / le above, this is needed */
232 inline void openpic_writefield_IPI(volatile u_int __iomem * addr, u_int mask, u_int field)
233 {
234         u_int  val = openpic_read_IPI(addr);
235         openpic_write(addr, (val & ~mask) | (field & mask));
236 }
237
238 static inline void openpic_clearfield_IPI(volatile u_int __iomem *addr, u_int mask)
239 {
240         openpic_writefield_IPI(addr, mask, 0);
241 }
242
243 static inline void openpic_setfield_IPI(volatile u_int __iomem *addr, u_int mask)
244 {
245         openpic_writefield_IPI(addr, mask, mask);
246 }
247
248 static void openpic_safe_writefield_IPI(volatile u_int __iomem *addr, u_int mask, u_int field)
249 {
250         openpic_setfield_IPI(addr, OPENPIC_MASK);
251
252         /* wait until it's not in use */
253         /* BenH: Is this code really enough ? I would rather check the result
254          *       and eventually retry ...
255          */
256         while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY);
257
258         openpic_writefield_IPI(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
259 }
260 #endif /* CONFIG_SMP */
261
262 #ifdef CONFIG_EPIC_SERIAL_MODE
263 /* On platforms that may use EPIC serial mode, the default is enabled. */
264 int epic_serial_mode = 1;
265
266 static void __init openpic_eicr_set_clk(u_int clkval)
267 {
268         openpic_writefield(&OpenPIC->Global.Global_Configuration1,
269                         OPENPIC_EICR_S_CLK_MASK, (clkval << 28));
270 }
271
272 static void __init openpic_enable_sie(void)
273 {
274         openpic_setfield(&OpenPIC->Global.Global_Configuration1,
275                         OPENPIC_EICR_SIE);
276 }
277 #endif
278
279 #if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PM)
280 static void openpic_reset(void)
281 {
282         openpic_setfield(&OpenPIC->Global.Global_Configuration0,
283                          OPENPIC_CONFIG_RESET);
284         while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
285                                  OPENPIC_CONFIG_RESET))
286                 mb();
287 }
288 #endif
289
290 void __init openpic_set_sources(int first_irq, int num_irqs, void __iomem *first_ISR)
291 {
292         volatile OpenPIC_Source __iomem *src = first_ISR;
293         int i, last_irq;
294
295         last_irq = first_irq + num_irqs;
296         if (last_irq > NumSources)
297                 NumSources = last_irq;
298         if (src == 0)
299                 src = &((struct OpenPIC __iomem *)OpenPIC_Addr)->Source[first_irq];
300         for (i = first_irq; i < last_irq; ++i, ++src)
301                 ISR[i] = src;
302 }
303
304 /*
305  * The `offset' parameter defines where the interrupts handled by the
306  * OpenPIC start in the space of interrupt numbers that the kernel knows
307  * about.  In other words, the OpenPIC's IRQ0 is numbered `offset' in the
308  * kernel's interrupt numbering scheme.
309  * We assume there is only one OpenPIC.
310  */
311 void __init openpic_init(int offset)
312 {
313         u_int t, i;
314         u_int timerfreq;
315         const char *version;
316
317         if (!OpenPIC_Addr) {
318                 printk("No OpenPIC found !\n");
319                 return;
320         }
321         OpenPIC = (volatile struct OpenPIC __iomem *)OpenPIC_Addr;
322
323 #ifdef CONFIG_EPIC_SERIAL_MODE
324         /* Have to start from ground zero.
325         */
326         openpic_reset();
327 #endif
328
329         if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122);
330
331         t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
332         switch (t & OPENPIC_FEATURE_VERSION_MASK) {
333         case 1:
334                 version = "1.0";
335                 break;
336         case 2:
337                 version = "1.2";
338                 break;
339         case 3:
340                 version = "1.3";
341                 break;
342         default:
343                 version = "?";
344                 break;
345         }
346         NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
347                          OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
348         if (NumSources == 0)
349                 openpic_set_sources(0,
350                                     ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
351                                      OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1,
352                                     NULL);
353         printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n",
354                version, NumProcessors, NumSources, OpenPIC);
355         timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
356         if (timerfreq)
357                 printk("OpenPIC timer frequency is %d.%06d MHz\n",
358                        timerfreq / 1000000, timerfreq % 1000000);
359
360         open_pic_irq_offset = offset;
361
362         /* Initialize timer interrupts */
363         if ( ppc_md.progress ) ppc_md.progress("openpic: timer",0x3ba);
364         for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
365                 /* Disabled, Priority 0 */
366                 openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+offset);
367                 /* No processor */
368                 openpic_maptimer(i, CPU_MASK_NONE);
369         }
370
371 #ifdef CONFIG_SMP
372         /* Initialize IPI interrupts */
373         if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb);
374         for (i = 0; i < OPENPIC_NUM_IPI; i++) {
375                 /* Disabled, Priority 10..13 */
376                 openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset);
377                 /* IPIs are per-CPU */
378                 irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
379                 irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
380         }
381 #endif
382
383         /* Initialize external interrupts */
384         if (ppc_md.progress) ppc_md.progress("openpic: external",0x3bc);
385
386         openpic_set_priority(0xf);
387
388         /* Init all external sources, including possibly the cascade. */
389         for (i = 0; i < NumSources; i++) {
390                 int sense;
391
392                 if (ISR[i] == 0)
393                         continue;
394
395                 /* the bootloader may have left it enabled (bad !) */
396                 openpic_disable_irq(i+offset);
397
398                 sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: \
399                                 (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE);
400
401                 if (sense & IRQ_SENSE_MASK)
402                         irq_desc[i+offset].status = IRQ_LEVEL;
403
404                 /* Enabled, Priority 8 */
405                 openpic_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
406                                 (sense & IRQ_SENSE_MASK));
407                 /* Processor 0 */
408                 openpic_mapirq(i, CPU_MASK_CPU0, CPU_MASK_NONE);
409         }
410
411         /* Init descriptors */
412         for (i = offset; i < NumSources + offset; i++)
413                 irq_desc[i].handler = &open_pic;
414
415         /* Initialize the spurious interrupt */
416         if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd);
417         openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
418         openpic_disable_8259_pass_through();
419 #ifdef CONFIG_EPIC_SERIAL_MODE
420         if (epic_serial_mode) {
421                 openpic_eicr_set_clk(7);        /* Slowest value until we know better */
422                 openpic_enable_sie();
423         }
424 #endif
425         openpic_set_priority(0);
426
427         if (ppc_md.progress) ppc_md.progress("openpic: exit",0x222);
428 }
429
430 #ifdef notused
431 static void openpic_enable_8259_pass_through(void)
432 {
433         openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
434                            OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
435 }
436 #endif /* notused */
437
438 static void openpic_disable_8259_pass_through(void)
439 {
440         openpic_setfield(&OpenPIC->Global.Global_Configuration0,
441                          OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
442 }
443
444 /*
445  *  Find out the current interrupt
446  */
447 u_int openpic_irq(void)
448 {
449         u_int vec;
450         DECL_THIS_CPU;
451
452         CHECK_THIS_CPU;
453         vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
454                                 OPENPIC_VECTOR_MASK);
455         return vec;
456 }
457
458 void openpic_eoi(void)
459 {
460         DECL_THIS_CPU;
461
462         CHECK_THIS_CPU;
463         openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
464         /* Handle PCI write posting */
465         (void)openpic_read(&OpenPIC->THIS_CPU.EOI);
466 }
467
468 #ifdef notused
469 static u_int openpic_get_priority(void)
470 {
471         DECL_THIS_CPU;
472
473         CHECK_THIS_CPU;
474         return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
475                                  OPENPIC_CURRENT_TASK_PRIORITY_MASK);
476 }
477 #endif /* notused */
478
479 void openpic_set_priority(u_int pri)
480 {
481         DECL_THIS_CPU;
482
483         CHECK_THIS_CPU;
484         check_arg_pri(pri);
485         openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
486                            OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
487 }
488
489 /*
490  *  Get/set the spurious vector
491  */
492 #ifdef notused
493 static u_int openpic_get_spurious(void)
494 {
495         return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
496                                  OPENPIC_VECTOR_MASK);
497 }
498 #endif /* notused */
499
500 static void openpic_set_spurious(u_int vec)
501 {
502         check_arg_vec(vec);
503         openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
504                            vec);
505 }
506
507 #ifdef CONFIG_SMP
508 /*
509  * Convert a cpu mask from logical to physical cpu numbers.
510  */
511 static inline cpumask_t physmask(cpumask_t cpumask)
512 {
513         int i;
514         cpumask_t mask = CPU_MASK_NONE;
515
516         cpus_and(cpumask, cpu_online_map, cpumask);
517
518         for (i = 0; i < NR_CPUS; i++)
519                 if (cpu_isset(i, cpumask))
520                         cpu_set(smp_hw_index[i], mask);
521
522         return mask;
523 }
524 #else
525 #define physmask(cpumask)       (cpumask)
526 #endif
527
528 void openpic_reset_processor_phys(u_int mask)
529 {
530         openpic_write(&OpenPIC->Global.Processor_Initialization, mask);
531 }
532
533 #if defined(CONFIG_SMP) || defined(CONFIG_PM)
534 static DEFINE_SPINLOCK(openpic_setup_lock);
535 #endif
536
537 #ifdef CONFIG_SMP
538 /*
539  *  Initialize an interprocessor interrupt (and disable it)
540  *
541  *  ipi: OpenPIC interprocessor interrupt number
542  *  pri: interrupt source priority
543  *  vec: the vector it will produce
544  */
545 static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec)
546 {
547         check_arg_ipi(ipi);
548         check_arg_pri(pri);
549         check_arg_vec(vec);
550         openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi),
551                                 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
552                                 (pri << OPENPIC_PRIORITY_SHIFT) | vec);
553 }
554
555 /*
556  *  Send an IPI to one or more CPUs
557  *
558  *  Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
559  *  and not a system-wide interrupt number
560  */
561 void openpic_cause_IPI(u_int ipi, cpumask_t cpumask)
562 {
563         cpumask_t phys;
564         DECL_THIS_CPU;
565
566         CHECK_THIS_CPU;
567         check_arg_ipi(ipi);
568         phys = physmask(cpumask);
569         openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
570                       cpus_addr(physmask(cpumask))[0]);
571 }
572
573 void openpic_request_IPIs(void)
574 {
575         int i;
576
577         /*
578          * Make sure this matches what is defined in smp.c for
579          * smp_message_{pass|recv}() or what shows up in
580          * /proc/interrupts will be wrong!!! --Troy */
581
582         if (OpenPIC == NULL)
583                 return;
584
585         /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */
586         request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset,
587                     openpic_ipi_action, SA_INTERRUPT,
588                     "IPI0 (call function)", NULL);
589         request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+1,
590                     openpic_ipi_action, SA_INTERRUPT,
591                     "IPI1 (reschedule)", NULL);
592         request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+2,
593                     openpic_ipi_action, SA_INTERRUPT,
594                     "IPI2 (invalidate tlb)", NULL);
595         request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+3,
596                     openpic_ipi_action, SA_INTERRUPT,
597                     "IPI3 (xmon break)", NULL);
598
599         for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
600                 openpic_enable_ipi(OPENPIC_VEC_IPI+open_pic_irq_offset+i);
601 }
602
603 /*
604  * Do per-cpu setup for SMP systems.
605  *
606  * Get IPI's working and start taking interrupts.
607  *   -- Cort
608  */
609
610 void __devinit do_openpic_setup_cpu(void)
611 {
612 #ifdef CONFIG_IRQ_ALL_CPUS
613         int i;
614         cpumask_t msk = CPU_MASK_NONE;
615 #endif
616         spin_lock(&openpic_setup_lock);
617
618 #ifdef CONFIG_IRQ_ALL_CPUS
619         cpu_set(smp_hw_index[smp_processor_id()], msk);
620
621         /* let the openpic know we want intrs. default affinity
622          * is 0xffffffff until changed via /proc
623          * That's how it's done on x86. If we want it differently, then
624          * we should make sure we also change the default values of irq_affinity
625          * in irq.c.
626          */
627         for (i = 0; i < NumSources; i++)
628                 openpic_mapirq(i, msk, CPU_MASK_ALL);
629 #endif /* CONFIG_IRQ_ALL_CPUS */
630         openpic_set_priority(0);
631
632         spin_unlock(&openpic_setup_lock);
633 }
634 #endif /* CONFIG_SMP */
635
636 /*
637  *  Initialize a timer interrupt (and disable it)
638  *
639  *  timer: OpenPIC timer number
640  *  pri: interrupt source priority
641  *  vec: the vector it will produce
642  */
643 static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec)
644 {
645         check_arg_timer(timer);
646         check_arg_pri(pri);
647         check_arg_vec(vec);
648         openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
649                                 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
650                                 (pri << OPENPIC_PRIORITY_SHIFT) | vec);
651 }
652
653 /*
654  *  Map a timer interrupt to one or more CPUs
655  */
656 static void __init openpic_maptimer(u_int timer, cpumask_t cpumask)
657 {
658         cpumask_t phys = physmask(cpumask);
659         check_arg_timer(timer);
660         openpic_write(&OpenPIC->Global.Timer[timer].Destination,
661                       cpus_addr(phys)[0]);
662 }
663
664 /*
665  * Initalize the interrupt source which will generate an NMI.
666  * This raises the interrupt's priority from 8 to 9.
667  *
668  * irq: The logical IRQ which generates an NMI.
669  */
670 void __init
671 openpic_init_nmi_irq(u_int irq)
672 {
673         check_arg_irq(irq);
674         openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
675                                 OPENPIC_PRIORITY_MASK,
676                                 9 << OPENPIC_PRIORITY_SHIFT);
677 }
678
679 /*
680  *
681  * All functions below take an offset'ed irq argument
682  *
683  */
684
685 /*
686  * Hookup a cascade to the OpenPIC.
687  */
688
689 static struct irqaction openpic_cascade_irqaction = {
690         .handler = no_action,
691         .flags = SA_INTERRUPT,
692         .mask = CPU_MASK_NONE,
693 };
694
695 void __init
696 openpic_hookup_cascade(u_int irq, char *name,
697         int (*cascade_fn)(struct pt_regs *))
698 {
699         openpic_cascade_irq = irq;
700         openpic_cascade_fn = cascade_fn;
701
702         if (setup_irq(irq, &openpic_cascade_irqaction))
703                 printk("Unable to get OpenPIC IRQ %d for cascade\n",
704                                 irq - open_pic_irq_offset);
705 }
706
707 /*
708  *  Enable/disable an external interrupt source
709  *
710  *  Externally called, irq is an offseted system-wide interrupt number
711  */
712 static void openpic_enable_irq(u_int irq)
713 {
714         volatile u_int __iomem *vpp;
715
716         check_arg_irq(irq);
717         vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority;
718         openpic_clearfield(vpp, OPENPIC_MASK);
719         /* make sure mask gets to controller before we return to user */
720         do {
721                 mb(); /* sync is probably useless here */
722         } while (openpic_readfield(vpp, OPENPIC_MASK));
723 }
724
725 static void openpic_disable_irq(u_int irq)
726 {
727         volatile u_int __iomem *vpp;
728         u32 vp;
729
730         check_arg_irq(irq);
731         vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority;
732         openpic_setfield(vpp, OPENPIC_MASK);
733         /* make sure mask gets to controller before we return to user */
734         do {
735                 mb();  /* sync is probably useless here */
736                 vp = openpic_readfield(vpp, OPENPIC_MASK | OPENPIC_ACTIVITY);
737         } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
738 }
739
740 #ifdef CONFIG_SMP
741 /*
742  *  Enable/disable an IPI interrupt source
743  *
744  *  Externally called, irq is an offseted system-wide interrupt number
745  */
746 void openpic_enable_ipi(u_int irq)
747 {
748         irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
749         check_arg_ipi(irq);
750         openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
751
752 }
753
754 void openpic_disable_ipi(u_int irq)
755 {
756         irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
757         check_arg_ipi(irq);
758         openpic_setfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
759 }
760 #endif
761
762 /*
763  *  Initialize an interrupt source (and disable it!)
764  *
765  *  irq: OpenPIC interrupt number
766  *  pri: interrupt source priority
767  *  vec: the vector it will produce
768  *  pol: polarity (1 for positive, 0 for negative)
769  *  sense: 1 for level, 0 for edge
770  */
771 static void __init
772 openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
773 {
774         openpic_safe_writefield(&ISR[irq]->Vector_Priority,
775                                 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
776                                 OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
777                                 (pri << OPENPIC_PRIORITY_SHIFT) | vec |
778                                 (pol ? OPENPIC_POLARITY_POSITIVE :
779                                         OPENPIC_POLARITY_NEGATIVE) |
780                                 (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
781 }
782
783 /*
784  *  Map an interrupt source to one or more CPUs
785  */
786 static void openpic_mapirq(u_int irq, cpumask_t physmask, cpumask_t keepmask)
787 {
788         if (ISR[irq] == 0)
789                 return;
790         if (!cpus_empty(keepmask)) {
791                 cpumask_t irqdest = { .bits[0] = openpic_read(&ISR[irq]->Destination) };
792                 cpus_and(irqdest, irqdest, keepmask);
793                 cpus_or(physmask, physmask, irqdest);
794         }
795         openpic_write(&ISR[irq]->Destination, cpus_addr(physmask)[0]);
796 }
797
798 #ifdef notused
799 /*
800  *  Set the sense for an interrupt source (and disable it!)
801  *
802  *  sense: 1 for level, 0 for edge
803  */
804 static void openpic_set_sense(u_int irq, int sense)
805 {
806         if (ISR[irq] != 0)
807                 openpic_safe_writefield(&ISR[irq]->Vector_Priority,
808                                         OPENPIC_SENSE_LEVEL,
809                                         (sense ? OPENPIC_SENSE_LEVEL : 0));
810 }
811 #endif /* notused */
812
813 /* No spinlocks, should not be necessary with the OpenPIC
814  * (1 register = 1 interrupt and we have the desc lock).
815  */
816 static void openpic_ack_irq(unsigned int irq_nr)
817 {
818 #ifdef __SLOW_VERSION__
819         openpic_disable_irq(irq_nr);
820         openpic_eoi();
821 #else
822         if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
823                 openpic_eoi();
824 #endif
825 }
826
827 static void openpic_end_irq(unsigned int irq_nr)
828 {
829 #ifdef __SLOW_VERSION__
830         if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
831             && irq_desc[irq_nr].action)
832                 openpic_enable_irq(irq_nr);
833 #else
834         if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
835                 openpic_eoi();
836 #endif
837 }
838
839 static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask)
840 {
841         openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask), CPU_MASK_NONE);
842 }
843
844 #ifdef CONFIG_SMP
845 static void openpic_ack_ipi(unsigned int irq_nr)
846 {
847         openpic_eoi();
848 }
849
850 static void openpic_end_ipi(unsigned int irq_nr)
851 {
852 }
853
854 static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
855 {
856         smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset, regs);
857         return IRQ_HANDLED;
858 }
859
860 #endif /* CONFIG_SMP */
861
862 int
863 openpic_get_irq(struct pt_regs *regs)
864 {
865         int irq = openpic_irq();
866
867         /*
868          * Check for the cascade interrupt and call the cascaded
869          * interrupt controller function (usually i8259_irq) if so.
870          * This should move to irq.c eventually.  -- paulus
871          */
872         if (irq == openpic_cascade_irq && openpic_cascade_fn != NULL) {
873                 int cirq = openpic_cascade_fn(regs);
874
875                 /* Allow for the cascade being shared with other devices */
876                 if (cirq != -1) {
877                         irq = cirq;
878                         openpic_eoi();
879                 }
880         } else if (irq == OPENPIC_VEC_SPURIOUS)
881                 irq = -1;
882         return irq;
883 }
884
885 #ifdef CONFIG_SMP
886 void
887 smp_openpic_message_pass(int target, int msg, unsigned long data, int wait)
888 {
889         cpumask_t mask = CPU_MASK_ALL;
890         /* make sure we're sending something that translates to an IPI */
891         if (msg > 0x3) {
892                 printk("SMP %d: smp_message_pass: unknown msg %d\n",
893                        smp_processor_id(), msg);
894                 return;
895         }
896         switch (target) {
897         case MSG_ALL:
898                 openpic_cause_IPI(msg, mask);
899                 break;
900         case MSG_ALL_BUT_SELF:
901                 cpu_clear(smp_processor_id(), mask);
902                 openpic_cause_IPI(msg, mask);
903                 break;
904         default:
905                 openpic_cause_IPI(msg, cpumask_of_cpu(target));
906                 break;
907         }
908 }
909 #endif /* CONFIG_SMP */
910
911 #ifdef CONFIG_PM
912
913 /*
914  * We implement the IRQ controller as a sysdev and put it
915  * to sleep at powerdown stage (the callback is named suspend,
916  * but it's old semantics, for the Device Model, it's really
917  * powerdown). The possible problem is that another sysdev that
918  * happens to be suspend after this one will have interrupts off,
919  * that may be an issue... For now, this isn't an issue on pmac
920  * though...
921  */
922
923 static u32 save_ipi_vp[OPENPIC_NUM_IPI];
924 static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES];
925 static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES];
926 static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS];
927 static int openpic_suspend_count;
928
929 static void openpic_cached_enable_irq(u_int irq)
930 {
931         check_arg_irq(irq);
932         save_irq_src_vp[irq - open_pic_irq_offset] &= ~OPENPIC_MASK;
933 }
934
935 static void openpic_cached_disable_irq(u_int irq)
936 {
937         check_arg_irq(irq);
938         save_irq_src_vp[irq - open_pic_irq_offset] |= OPENPIC_MASK;
939 }
940
941 /* WARNING: Can be called directly by the cpufreq code with NULL parameter,
942  * we need something better to deal with that... Maybe switch to S1 for
943  * cpufreq changes
944  */
945 int openpic_suspend(struct sys_device *sysdev, u32 state)
946 {
947         int     i;
948         unsigned long flags;
949
950         spin_lock_irqsave(&openpic_setup_lock, flags);
951
952         if (openpic_suspend_count++ > 0) {
953                 spin_unlock_irqrestore(&openpic_setup_lock, flags);
954                 return 0;
955         }
956
957         openpic_set_priority(0xf);
958
959         open_pic.enable = openpic_cached_enable_irq;
960         open_pic.disable = openpic_cached_disable_irq;
961
962         for (i=0; i<NumProcessors; i++) {
963                 save_cpu_task_pri[i] = openpic_read(&OpenPIC->Processor[i].Current_Task_Priority);
964                 openpic_writefield(&OpenPIC->Processor[i].Current_Task_Priority,
965                                    OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf);
966         }
967
968         for (i=0; i<OPENPIC_NUM_IPI; i++)
969                 save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i));
970         for (i=0; i<NumSources; i++) {
971                 if (ISR[i] == 0)
972                         continue;
973                 save_irq_src_vp[i] = openpic_read(&ISR[i]->Vector_Priority) & ~OPENPIC_ACTIVITY;
974                 save_irq_src_dest[i] = openpic_read(&ISR[i]->Destination);
975         }
976
977         spin_unlock_irqrestore(&openpic_setup_lock, flags);
978
979         return 0;
980 }
981
982 /* WARNING: Can be called directly by the cpufreq code with NULL parameter,
983  * we need something better to deal with that... Maybe switch to S1 for
984  * cpufreq changes
985  */
986 int openpic_resume(struct sys_device *sysdev)
987 {
988         int             i;
989         unsigned long   flags;
990         u32             vppmask =       OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
991                                         OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK |
992                                         OPENPIC_MASK;
993
994         spin_lock_irqsave(&openpic_setup_lock, flags);
995
996         if ((--openpic_suspend_count) > 0) {
997                 spin_unlock_irqrestore(&openpic_setup_lock, flags);
998                 return 0;
999         }
1000
1001         openpic_reset();
1002
1003         /* OpenPIC sometimes seem to need some time to be fully back up... */
1004         do {
1005                 openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
1006         } while(openpic_readfield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK)
1007                         != OPENPIC_VEC_SPURIOUS);
1008         
1009         openpic_disable_8259_pass_through();
1010
1011         for (i=0; i<OPENPIC_NUM_IPI; i++)
1012                 openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i),
1013                               save_ipi_vp[i]);
1014         for (i=0; i<NumSources; i++) {
1015                 if (ISR[i] == 0)
1016                         continue;
1017                 openpic_write(&ISR[i]->Destination, save_irq_src_dest[i]);
1018                 openpic_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]);
1019                 /* make sure mask gets to controller before we return to user */
1020                 do {
1021                         openpic_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]);
1022                 } while (openpic_readfield(&ISR[i]->Vector_Priority, vppmask)
1023                          != (save_irq_src_vp[i] & vppmask));
1024         }
1025         for (i=0; i<NumProcessors; i++)
1026                 openpic_write(&OpenPIC->Processor[i].Current_Task_Priority,
1027                               save_cpu_task_pri[i]);
1028
1029         open_pic.enable = openpic_enable_irq;
1030         open_pic.disable = openpic_disable_irq;
1031
1032         openpic_set_priority(0);
1033
1034         spin_unlock_irqrestore(&openpic_setup_lock, flags);
1035
1036         return 0;
1037 }
1038
1039 #endif /* CONFIG_PM */
1040
1041 static struct sysdev_class openpic_sysclass = {
1042         set_kset_name("openpic"),
1043 };
1044
1045 static struct sys_device device_openpic = {
1046         .id             = 0,
1047         .cls            = &openpic_sysclass,
1048 };
1049
1050 static struct sysdev_driver driver_openpic = {
1051 #ifdef CONFIG_PM
1052         .suspend        = &openpic_suspend,
1053         .resume         = &openpic_resume,
1054 #endif /* CONFIG_PM */
1055 };
1056
1057 static int __init init_openpic_sysfs(void)
1058 {
1059         int rc;
1060
1061         if (!OpenPIC_Addr)
1062                 return -ENODEV;
1063         printk(KERN_DEBUG "Registering openpic with sysfs...\n");
1064         rc = sysdev_class_register(&openpic_sysclass);
1065         if (rc) {
1066                 printk(KERN_ERR "Failed registering openpic sys class\n");
1067                 return -ENODEV;
1068         }
1069         rc = sysdev_register(&device_openpic);
1070         if (rc) {
1071                 printk(KERN_ERR "Failed registering openpic sys device\n");
1072                 return -ENODEV;
1073         }
1074         rc = sysdev_driver_register(&openpic_sysclass, &driver_openpic);
1075         if (rc) {
1076                 printk(KERN_ERR "Failed registering openpic sys driver\n");
1077                 return -ENODEV;
1078         }
1079         return 0;
1080 }
1081
1082 subsys_initcall(init_openpic_sysfs);
1083