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