File: /usr/src/linux/arch/ppc/kernel/open_pic.c

1     /*
2      * BK Id: SCCS/s.open_pic.c 1.28 09/08/01 15:47:42 paulus
3      */
4     /*
5      *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
6      *
7      *  Copyright (C) 1997 Geert Uytterhoeven
8      *
9      *  This file is subject to the terms and conditions of the GNU General Public
10      *  License.  See the file COPYING in the main directory of this archive
11      *  for more details.
12      */
13     
14     #include <linux/config.h>
15     #include <linux/types.h>
16     #include <linux/kernel.h>
17     #include <linux/sched.h>
18     #include <linux/init.h>
19     #include <linux/irq.h>
20     #include <linux/init.h>
21     #include <asm/ptrace.h>
22     #include <asm/signal.h>
23     #include <asm/io.h>
24     #include <asm/irq.h>
25     #include <asm/prom.h>
26     #include <asm/sections.h>
27     
28     #include "local_irq.h"
29     #include "open_pic.h"
30     #include "open_pic_defs.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     extern int use_of_interrupt_tree;
37     
38     void find_ISUs(void);
39     
40     static u_int NumProcessors;
41     static u_int NumSources;
42     #ifdef CONFIG_POWER3
43     static int NumISUs;
44     #endif
45     static int open_pic_irq_offset;
46     static volatile unsigned char* chrp_int_ack_special;
47     
48     OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
49     
50     /* Global Operations */
51     static void openpic_disable_8259_pass_through(void);
52     static void openpic_set_priority(u_int pri);
53     static void openpic_set_spurious(u_int vector);
54     
55     #ifdef CONFIG_SMP
56     /* Interprocessor Interrupts */
57     static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
58     static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
59     #endif
60     
61     /* Timer Interrupts */
62     static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
63     static void openpic_maptimer(u_int timer, u_int cpumask);
64     
65     /* Interrupt Sources */
66     static void openpic_enable_irq(u_int irq);
67     static void openpic_disable_irq(u_int irq);
68     static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
69     			    int is_level);
70     static void openpic_mapirq(u_int irq, u_int cpumask);
71     
72     /*
73      * These functions are not used but the code is kept here
74      * for completeness and future reference.
75      */
76     static void openpic_reset(void);
77     #ifdef notused
78     static void openpic_enable_8259_pass_through(void);
79     static u_int openpic_get_priority(void);
80     static u_int openpic_get_spurious(void);
81     static void openpic_set_sense(u_int irq, int sense);
82     #endif /* notused */
83     
84     /*
85      * Description of the openpic for the higher-level irq code
86      */
87     static void openpic_end_irq(unsigned int irq_nr);
88     static void openpic_ack_irq(unsigned int irq_nr);
89     static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
90     
91     struct hw_interrupt_type open_pic = {
92     	" OpenPIC  ",
93     	NULL,
94     	NULL,
95     	openpic_enable_irq,
96     	openpic_disable_irq,
97     	openpic_ack_irq,
98     	openpic_end_irq,
99     	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     	" OpenPIC  ",
110     	NULL,
111     	NULL,
112     	openpic_enable_ipi,
113     	openpic_disable_ipi,
114     	openpic_ack_ipi,
115     	openpic_end_ipi,
116     	0
117     };
118     #endif /* CONFIG_SMP */
119     
120     /*
121      *  Accesses to the current processor's openpic registers
122      */
123     #ifdef CONFIG_SMP
124     #define THIS_CPU		Processor[cpu]
125     #define DECL_THIS_CPU		int cpu = smp_hw_index[smp_processor_id()]
126     #define CHECK_THIS_CPU		check_arg_cpu(cpu)
127     #else
128     #define THIS_CPU		Processor[0]
129     #define DECL_THIS_CPU
130     #define CHECK_THIS_CPU
131     #endif /* CONFIG_SMP */
132     
133     #if 1
134     #define check_arg_ipi(ipi) \
135         if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
136     	printk("open_pic.c:%d: illegal ipi %d\n", __LINE__, ipi);
137     #define check_arg_timer(timer) \
138         if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
139     	printk("open_pic.c:%d: illegal timer %d\n", __LINE__, timer);
140     #define check_arg_vec(vec) \
141         if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
142     	printk("open_pic.c:%d: illegal vector %d\n", __LINE__, vec);
143     #define check_arg_pri(pri) \
144         if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
145     	printk("open_pic.c:%d: illegal priority %d\n", __LINE__, pri);
146     /*
147      * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
148      * data has probably been corrupted and we're going to panic or deadlock later
149      * anyway --Troy
150      */
151     extern unsigned long* _get_SP(void);
152     #define check_arg_irq(irq) \
153         if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ \
154           printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
155           print_backtrace(_get_SP()); }
156     #define check_arg_cpu(cpu) \
157         if (cpu < 0 || cpu >= NumProcessors){ \
158     	printk("open_pic.c:%d: illegal cpu %d\n", __LINE__, cpu); \
159     	print_backtrace(_get_SP()); }
160     #else
161     #define check_arg_ipi(ipi)	do {} while (0)
162     #define check_arg_timer(timer)	do {} while (0)
163     #define check_arg_vec(vec)	do {} while (0)
164     #define check_arg_pri(pri)	do {} while (0)
165     #define check_arg_irq(irq)	do {} while (0)
166     #define check_arg_cpu(cpu)	do {} while (0)
167     #endif
168     
169     #ifdef CONFIG_POWER3
170     	#define GET_ISU(source)	ISU[(source) >> 4][(source) & 0xf]
171     #else
172     	#define GET_ISU(source)	ISU[0][(source)]
173     #endif
174     
175     u_int openpic_read(volatile u_int *addr)
176     {
177     	u_int val;
178     
179     	val = in_le32(addr);
180     	return val;
181     }
182     
183     static inline void openpic_write(volatile u_int *addr, u_int val)
184     {
185     	out_le32(addr, val);
186     }
187     
188     static inline u_int openpic_readfield(volatile u_int *addr, u_int mask)
189     {
190     	u_int val = openpic_read(addr);
191     	return val & mask;
192     }
193     
194     inline void openpic_writefield(volatile u_int *addr, u_int mask,
195     			       u_int field)
196     {
197     	u_int val = openpic_read(addr);
198     	openpic_write(addr, (val & ~mask) | (field & mask));
199     }
200     
201     static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
202     {
203     	openpic_writefield(addr, mask, 0);
204     }
205     
206     static inline void openpic_setfield(volatile u_int *addr, u_int mask)
207     {
208     	openpic_writefield(addr, mask, mask);
209     }
210     
211     static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
212     				    u_int field)
213     {
214     	openpic_setfield(addr, OPENPIC_MASK);
215     	while (openpic_read(addr) & OPENPIC_ACTIVITY);
216     	openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
217     }
218     
219     #ifdef CONFIG_SMP
220     /* yes this is right ... bug, feature, you decide! -- tgall */
221     u_int openpic_read_IPI(volatile u_int* addr)
222     {
223              u_int val = 0;
224     #ifdef CONFIG_POWER3
225             val = in_be32(addr);
226     #else
227             val = in_le32(addr);
228     #endif
229             return val;
230     }
231     
232     /* because of the power3 be / le above, this is needed */
233     inline void openpic_writefield_IPI(volatile u_int* addr, u_int mask, u_int field)
234     {
235             u_int  val = openpic_read_IPI(addr);
236             openpic_write(addr, (val & ~mask) | (field & mask));
237     }
238     
239     static inline void openpic_clearfield_IPI(volatile u_int *addr, u_int mask)
240     {
241             openpic_writefield_IPI(addr, mask, 0);
242     }
243     
244     static inline void openpic_setfield_IPI(volatile u_int *addr, u_int mask)
245     {
246             openpic_writefield_IPI(addr, mask, mask);
247     }
248     
249     static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int field)
250     {
251             openpic_setfield_IPI(addr, OPENPIC_MASK);
252     
253             /* wait until it's not in use */
254             /* BenH: Is this code really enough ? I would rather check the result
255              *       and eventually retry ...
256              */
257             while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY);
258     
259             openpic_writefield_IPI(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
260     }
261     #endif /* CONFIG_SMP */
262     
263     void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
264     			 int programmer_switch_irq)
265     {
266     	u_int t, i;
267     	u_int timerfreq;
268     	const char *version;
269     
270     	if (!OpenPIC_Addr) {
271     		printk("No OpenPIC found !\n");
272     		return;
273     	}
274     	OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
275     
276     	if ( ppc_md.progress ) ppc_md.progress("openpic enter",0x122);
277     
278     	t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
279     	switch (t & OPENPIC_FEATURE_VERSION_MASK) {
280     	case 1:
281     		version = "1.0";
282     		break;
283     	case 2:
284     		version = "1.2";
285     		break;
286     	case 3:
287     		version = "1.3";
288     		break;
289     	default:
290     		version = "?";
291     		break;
292     	}
293     	NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
294     			 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
295     	NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
296     		      OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
297     	printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n",
298     	       version, NumProcessors, NumSources, OpenPIC);
299     	timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
300     	if (timerfreq)
301     		printk("OpenPIC timer frequency is %d.%06d MHz\n",
302     		       timerfreq / 1000000, timerfreq % 1000000);
303     
304     	if (!main_pic)
305     		return;
306     
307     	open_pic_irq_offset = offset;
308     	chrp_int_ack_special = (volatile unsigned char*)chrp_ack;
309     
310     	/* Initialize timer interrupts */
311     	if ( ppc_md.progress ) ppc_md.progress("openpic timer",0x3ba);
312     	for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
313     		/* Disabled, Priority 0 */
314     		openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+offset);
315     		/* No processor */
316     		openpic_maptimer(i, 0);
317     	}
318     
319     #ifdef CONFIG_SMP
320     	/* Initialize IPI interrupts */
321     	if ( ppc_md.progress ) ppc_md.progress("openpic ipi",0x3bb);
322     	for (i = 0; i < OPENPIC_NUM_IPI; i++) {
323     		/* Disabled, Priority 10..13 */
324     		openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset);
325     		/* IPIs are per-CPU */
326     		irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
327     		irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
328     	}
329     #endif
330     
331     	find_ISUs();
332     
333     	/* Initialize external interrupts */
334     	if (ppc_md.progress) ppc_md.progress("openpic ext",0x3bc);
335     
336     	openpic_set_priority(0xf);
337     
338     	/* SIOint (8259 cascade) is special */
339     	if (offset) {
340     		openpic_initirq(0, 8, offset, 1, 1);
341     		openpic_mapirq(0, 1<<0);
342     	}
343     
344     	/* Init all external sources */
345     	for (i = 1; i < NumSources; i++) {
346     		int pri, sense;
347     
348     		/* the bootloader may have left it enabled (bad !) */
349     		openpic_disable_irq(i+offset);
350     
351     		pri = (i == programmer_switch_irq)? 9: 8;
352     		sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
353     		if (sense)
354     			irq_desc[i+offset].status = IRQ_LEVEL;
355     
356     		/* Enabled, Priority 8 or 9 */
357     		openpic_initirq(i, pri, i+offset, !sense, sense);
358     		/* Processor 0 */
359     		openpic_mapirq(i, 1<<0);
360     	}
361     
362     	/* Init descriptors */
363     	for (i = offset; i < NumSources + offset; i++)
364     		irq_desc[i].handler = &open_pic;
365     
366     	/* Initialize the spurious interrupt */
367     	if (ppc_md.progress) ppc_md.progress("openpic spurious",0x3bd);
368     	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+offset);
369     
370     	/* Initialize the cascade */
371     	if (offset) {
372     		if (request_irq(offset, no_action, SA_INTERRUPT,
373     				"82c59 cascade", NULL))
374     			printk("Unable to get OpenPIC IRQ 0 for cascade\n");
375     	}
376     	openpic_set_priority(0);
377     	openpic_disable_8259_pass_through();
378     
379     	if (ppc_md.progress) ppc_md.progress("openpic exit",0x222);
380     }
381     
382     #ifdef CONFIG_POWER3
383     void openpic_setup_ISU(int isu_num, unsigned long addr)
384     {
385     	if (isu_num >= OPENPIC_MAX_ISU)
386     		return;
387     	ISU[isu_num] = (OpenPIC_SourcePtr) ioremap(addr, 0x400);
388     	if (isu_num >= NumISUs)
389     		NumISUs = isu_num + 1;
390     }
391     #endif
392     
393     void find_ISUs(void)
394     {
395     #ifdef CONFIG_POWER3
396             /* Use /interrupt-controller/reg and
397              * /interrupt-controller/interrupt-ranges from OF device tree
398     	 * the ISU array is setup in chrp_pci.c in ibm_add_bridges
399     	 * as a result
400     	 * -- tgall
401              */
402     
403     	/* basically each ISU is a bus, and this assumes that
404     	 * open_pic_isu_count interrupts per bus are possible 
405     	 * ISU == Interrupt Source
406     	 */
407     	NumSources = NumISUs * 0x10;
408     
409     #else
410     	/* for non-distributed OpenPIC implementations it's in the IDU -- Cort */
411     	ISU[0] = (OpenPIC_Source *)OpenPIC->Source;
412     #endif
413     }
414     
415     static void openpic_reset(void)
416     {
417     	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
418     			 OPENPIC_CONFIG_RESET);
419     	while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
420     				 OPENPIC_CONFIG_RESET))
421     		mb();
422     }
423     
424     #ifdef notused
425     static void openpic_enable_8259_pass_through(void)
426     {
427     	openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
428     			   OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
429     }
430     #endif /* notused */
431     
432     static void openpic_disable_8259_pass_through(void)
433     {
434     	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
435     			 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
436     }
437     
438     /*
439      *  Find out the current interrupt
440      */
441     u_int openpic_irq(void)
442     {
443     	u_int vec;
444     	DECL_THIS_CPU;
445     
446     	CHECK_THIS_CPU;
447     	vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
448     				OPENPIC_VECTOR_MASK);
449     	return vec;
450     }
451     
452     void openpic_eoi(void)
453     {
454     	DECL_THIS_CPU;
455     
456     	CHECK_THIS_CPU;
457     	openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
458     	/* Handle PCI write posting */
459     	(void)openpic_read(&OpenPIC->THIS_CPU.EOI);
460     }
461     
462     #ifdef notused
463     static u_int openpic_get_priority(void)
464     {
465     	DECL_THIS_CPU;
466     
467     	CHECK_THIS_CPU;
468     	return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
469     				 OPENPIC_CURRENT_TASK_PRIORITY_MASK);
470     }
471     #endif /* notused */
472     
473     static void openpic_set_priority(u_int pri)
474     {
475     	DECL_THIS_CPU;
476     
477     	CHECK_THIS_CPU;
478     	check_arg_pri(pri);
479     	openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
480     			   OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
481     }
482     
483     /*
484      *  Get/set the spurious vector
485      */
486     #ifdef notused
487     static u_int openpic_get_spurious(void)
488     {
489     	return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
490     				 OPENPIC_VECTOR_MASK);
491     }
492     #endif /* notused */
493     
494     static void openpic_set_spurious(u_int vec)
495     {
496     	check_arg_vec(vec);
497     	openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
498     			   vec);
499     }
500     
501     #ifdef CONFIG_SMP
502     /*
503      * Convert a cpu mask from logical to physical cpu numbers.
504      */
505     static inline u32 physmask(u32 cpumask)
506     {
507     	int i;
508     	u32 mask = 0;
509     
510     	for (i = 0; i < smp_num_cpus; ++i, cpumask >>= 1)
511     		mask |= (cpumask & 1) << smp_hw_index[i];
512     	return mask;
513     }
514     #else
515     #define physmask(cpumask)	(cpumask)
516     #endif
517     
518     void openpic_init_processor(u_int cpumask)
519     {
520     	openpic_write(&OpenPIC->Global.Processor_Initialization,
521     		      physmask(cpumask));
522     }
523     
524     static spinlock_t openpic_setup_lock = SPIN_LOCK_UNLOCKED;
525     
526     #ifdef CONFIG_SMP
527     /*
528      *  Initialize an interprocessor interrupt (and disable it)
529      *
530      *  ipi: OpenPIC interprocessor interrupt number
531      *  pri: interrupt source priority
532      *  vec: the vector it will produce
533      */
534     static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec)
535     {
536     	check_arg_ipi(ipi);
537     	check_arg_pri(pri);
538     	check_arg_vec(vec);
539     	openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi),
540     				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
541     				(pri << OPENPIC_PRIORITY_SHIFT) | vec);
542     }
543     
544     /*
545      *  Send an IPI to one or more CPUs
546      *  
547      *  Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
548      *  and not a system-wide interrupt number
549      */
550     void openpic_cause_IPI(u_int ipi, u_int cpumask)
551     {
552     	DECL_THIS_CPU;
553     
554     	CHECK_THIS_CPU;
555     	check_arg_ipi(ipi);
556     	openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
557     		      physmask(cpumask));
558     }
559     
560     void openpic_request_IPIs(void)
561     {
562     	int i;
563     	
564     	/*
565     	 * Make sure this matches what is defined in smp.c for 
566     	 * smp_message_{pass|recv}() or what shows up in 
567     	 * /proc/interrupts will be wrong!!! --Troy */
568     	
569     	if (OpenPIC == NULL)
570     		return;
571     
572     	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset,
573     		    openpic_ipi_action, 0, "IPI0 (call function)", 0);
574     	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+1,
575     		    openpic_ipi_action, 0, "IPI1 (reschedule)", 0);
576     	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+2,
577     		    openpic_ipi_action, 0, "IPI2 (invalidate tlb)", 0);
578     	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+3,
579     		    openpic_ipi_action, 0, "IPI3 (xmon break)", 0);
580     
581     	for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
582     		openpic_enable_ipi(OPENPIC_VEC_IPI+open_pic_irq_offset+i);
583     }
584     
585     /*
586      * Do per-cpu setup for SMP systems.
587      *
588      * Get IPI's working and start taking interrupts.
589      *   -- Cort
590      */
591     
592     void __init do_openpic_setup_cpu(void)
593     {
594      	int i;
595     	u32 msk = 1 << smp_hw_index[smp_processor_id()];
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     		      physmask(cpumask));
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     	check_arg_irq(irq);
658     	openpic_clearfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
659     	/* make sure mask gets to controller before we return to user */
660     	do {
661     		mb(); /* sync is probably useless here */
662     	} while(openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
663     			OPENPIC_MASK));
664     }
665     
666     static void openpic_disable_irq(u_int irq)
667     {
668     	u32 vp;
669     	
670     	check_arg_irq(irq);
671     	openpic_setfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
672     	/* make sure mask gets to controller before we return to user */
673     	do {
674     		mb();  /* sync is probably useless here */
675     		vp = openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
676         			OPENPIC_MASK | OPENPIC_ACTIVITY);
677     	} while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
678     }
679     
680     #ifdef CONFIG_SMP
681     /*
682      *  Enable/disable an IPI interrupt source
683      *  
684      *  Externally called, irq is an offseted system-wide interrupt number
685      */
686     void openpic_enable_ipi(u_int irq)
687     {
688     	irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
689     	check_arg_ipi(irq);
690     	openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
691     
692     }
693     
694     void openpic_disable_ipi(u_int irq)
695     {
696     	irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
697     	check_arg_ipi(irq);
698     	openpic_setfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
699     }
700     #endif
701     
702     /*
703      *  Initialize an interrupt source (and disable it!)
704      *
705      *  irq: OpenPIC interrupt number
706      *  pri: interrupt source priority
707      *  vec: the vector it will produce
708      *  pol: polarity (1 for positive, 0 for negative)
709      *  sense: 1 for level, 0 for edge
710      */
711     static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
712     {
713     	openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
714     				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
715     				OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
716     				(pri << OPENPIC_PRIORITY_SHIFT) | vec |
717     				(pol ? OPENPIC_POLARITY_POSITIVE :
718     			    		OPENPIC_POLARITY_NEGATIVE) |
719     				(sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
720     }
721     
722     /*
723      *  Map an interrupt source to one or more CPUs
724      */
725     static void openpic_mapirq(u_int irq, u_int physmask)
726     {
727     	openpic_write(&GET_ISU(irq).Destination, physmask);
728     }
729     
730     #ifdef notused
731     /*
732      *  Set the sense for an interrupt source (and disable it!)
733      *
734      *  sense: 1 for level, 0 for edge
735      */
736     static void openpic_set_sense(u_int irq, int sense)
737     {
738     	openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
739     				OPENPIC_SENSE_LEVEL,
740     				(sense ? OPENPIC_SENSE_LEVEL : 0));
741     }
742     #endif /* notused */
743     
744     /* No spinlocks, should not be necessary with the OpenPIC
745      * (1 register = 1 interrupt and we have the desc lock).
746      */
747     static void openpic_ack_irq(unsigned int irq_nr)
748     {
749     	openpic_disable_irq(irq_nr);
750     	openpic_eoi();
751     }
752     
753     static void openpic_end_irq(unsigned int irq_nr)
754     {
755     	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
756     		openpic_enable_irq(irq_nr);
757     }
758     
759     static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
760     {
761     	openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask));
762     }
763     
764     #ifdef CONFIG_SMP
765     static void openpic_ack_ipi(unsigned int irq_nr)
766     {
767     	openpic_eoi();
768     }
769     
770     static void openpic_end_ipi(unsigned int irq_nr)
771     {
772     }
773     
774     static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
775     {
776     	smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset, regs);
777     }
778     
779     #endif /* CONFIG_SMP */
780     
781     /* This one may be merged with PReP and CHRP */
782     int
783     openpic_get_irq(struct pt_regs *regs)
784     {
785     /*
786      * Clean up needed. -VAL
787      */
788     #ifndef CONFIG_GEMINI
789     	extern int i8259_irq(int cpu);
790     #endif
791     	int irq = openpic_irq();
792     
793     	/* Management of the cascade should be moved out of here */
794     
795     	/* Yep - because openpic !=> i8259, for one thing. -VAL */
796             if (open_pic_irq_offset && irq == open_pic_irq_offset)
797             {
798                     /*
799                      * This magic address generates a PCI IACK cycle.
800                      */
801     		if ( chrp_int_ack_special )
802     			irq = *chrp_int_ack_special;
803     #ifndef CONFIG_GEMINI
804     		else
805     			irq = i8259_irq( smp_processor_id() );
806     #endif
807     		openpic_eoi();
808             }
809     	if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
810     		irq = -1;
811     	return irq;
812     }
813     
814     #ifdef CONFIG_SMP
815     void
816     smp_openpic_message_pass(int target, int msg, unsigned long data, int wait)
817     {
818     	/* make sure we're sending something that translates to an IPI */
819     	if (msg > 0x3) {
820     		printk("SMP %d: smp_message_pass: unknown msg %d\n",
821     		       smp_processor_id(), msg);
822     		return;
823     	}
824     	switch (target) {
825     	case MSG_ALL:
826     		openpic_cause_IPI(msg, 0xffffffff);
827     		break;
828     	case MSG_ALL_BUT_SELF:
829     		openpic_cause_IPI(msg,
830     				  0xffffffff & ~(1 << smp_processor_id()));
831     		break;
832     	default:
833     		openpic_cause_IPI(msg, 1<<target);
834     		break;
835     	}
836     }
837     #endif /* CONFIG_SMP */
838     
839     #ifdef CONFIG_PMAC_PBOOK
840     static u32 save_ipi_vp[OPENPIC_NUM_IPI];
841     static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES];
842     static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES];
843     static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS];
844     
845     void __pmac
846     openpic_sleep_save_intrs(void)
847     {
848     	int	i;
849     	unsigned long flags;
850     	
851     	spin_lock_irqsave(&openpic_setup_lock, flags);
852     
853     	for (i=0; i<NumProcessors; i++) {
854     		save_cpu_task_pri[i] = openpic_read(&OpenPIC->Processor[i].Current_Task_Priority);
855     		openpic_writefield(&OpenPIC->Processor[i].Current_Task_Priority,
856     				   OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf);
857     	}
858     
859     	for (i=0; i<OPENPIC_NUM_IPI; i++)
860     		save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i));
861     	for (i=0; i<NumSources; i++) {
862     		save_irq_src_vp[i] = openpic_read(&OpenPIC->Source[i].Vector_Priority)
863     			& ~OPENPIC_ACTIVITY;
864     		save_irq_src_dest[i] = openpic_read(&OpenPIC->Source[i].Destination);
865     	}
866     	spin_unlock_irqrestore(&openpic_setup_lock, flags);
867     }
868     
869     void __pmac
870     openpic_sleep_restore_intrs(void)
871     {
872     	int		i;
873     	unsigned long	flags;
874     
875     	spin_lock_irqsave(&openpic_setup_lock, flags);
876     	
877     	openpic_reset();
878     
879     	for (i=0; i<OPENPIC_NUM_IPI; i++)
880     		openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i), save_ipi_vp[i]);
881     	for (i=0; i<NumSources; i++) {
882     		openpic_write(&OpenPIC->Source[i].Vector_Priority, save_irq_src_vp[i]);
883     		openpic_write(&OpenPIC->Source[i].Destination, save_irq_src_dest[i]);
884     	}
885     	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+open_pic_irq_offset);
886     	openpic_disable_8259_pass_through();
887     	for (i=0; i<NumProcessors; i++)
888     		openpic_write(&OpenPIC->Processor[i].Current_Task_Priority, save_cpu_task_pri[i]);
889     
890     	spin_unlock_irqrestore(&openpic_setup_lock, flags);
891     }
892     #endif /* CONFIG_PMAC_PBOOK */
893