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/pgtable.h>
21 #include <asm/irq.h>
22 #include <asm/prom.h>
23 #include <asm/smp.h>
24 #include <asm/machdep.h>
25 
26 #include "local_irq.h"
27 #include "open_pic.h"
28 #include "open_pic_defs.h"
29 #include "i8259.h"
30 #include <asm/ppcdebug.h>
31 
32 void* OpenPIC_Addr;
33 static volatile struct OpenPIC *OpenPIC = NULL;
34 u_int OpenPIC_NumInitSenses __initdata = 0;
35 u_char *OpenPIC_InitSenses __initdata = NULL;
36 
37 void find_ISUs(void);
38 
39 static u_int NumProcessors;
40 static u_int NumSources;
41 static int NumISUs;
42 static int open_pic_irq_offset;
43 static volatile unsigned char* chrp_int_ack_special;
44 static int broken_ipi_registers;
45 
46 OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
47 
48 static void openpic_end_irq(unsigned int irq_nr);
49 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
50 
51 struct hw_interrupt_type open_pic = {
52 	" OpenPIC  ",
53 	NULL,
54 	NULL,
55 	openpic_enable_irq,
56 	openpic_disable_irq,
57 	NULL,
58 	openpic_end_irq,
59 	openpic_set_affinity
60 };
61 
62 #ifdef CONFIG_SMP
63 static void openpic_end_ipi(unsigned int irq_nr);
64 static void openpic_enable_ipi(unsigned int irq_nr);
65 static void openpic_disable_ipi(unsigned int irq_nr);
66 
67 struct hw_interrupt_type open_pic_ipi = {
68 	" OpenPIC  ",
69 	NULL,
70 	NULL,
71 	openpic_enable_ipi,
72 	openpic_disable_ipi,
73 	NULL,
74 	openpic_end_ipi,
75 	NULL
76 };
77 #endif /* CONFIG_SMP */
78 
79 unsigned int openpic_vec_ipi;
80 unsigned int openpic_vec_timer;
81 unsigned int openpic_vec_spurious;
82 
83 /*
84  *  Accesses to the current processor's openpic registers
85  */
86 #ifdef CONFIG_SMP
87 #define THIS_CPU		Processor[cpu]
88 #define DECL_THIS_CPU		int cpu = hard_smp_processor_id()
89 #define CHECK_THIS_CPU		check_arg_cpu(cpu)
90 #else
91 #define THIS_CPU		Processor[hard_smp_processor_id()]
92 #define DECL_THIS_CPU
93 #define CHECK_THIS_CPU
94 #endif /* CONFIG_SMP */
95 
96 #if 1
97 #define check_arg_ipi(ipi) \
98     if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
99 	printk(KERN_ERR "open_pic.c:%d: illegal ipi %d\n", __LINE__, ipi);
100 #define check_arg_timer(timer) \
101     if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
102 	printk(KERN_ERR "open_pic.c:%d: illegal timer %d\n", __LINE__, timer);
103 #define check_arg_vec(vec) \
104     if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
105 	printk(KERN_ERR "open_pic.c:%d: illegal vector %d\n", __LINE__, vec);
106 #define check_arg_pri(pri) \
107     if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
108 	printk(KERN_ERR "open_pic.c:%d: illegal priority %d\n", __LINE__, pri);
109 /*
110  * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
111  * data has probably been corrupted and we're going to panic or deadlock later
112  * anyway --Troy
113  */
114 extern unsigned long* _get_SP(void);
115 #define check_arg_irq(irq) \
116     if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ \
117       printk(KERN_ERR "open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
118       print_backtrace(_get_SP()); }
119 #define check_arg_cpu(cpu) \
120     if (cpu < 0 || cpu >= OPENPIC_MAX_PROCESSORS){ \
121 	printk(KERN_ERR "open_pic.c:%d: illegal cpu %d\n", __LINE__, cpu); \
122 	print_backtrace(_get_SP()); }
123 #else
124 #define check_arg_ipi(ipi)	do {} while (0)
125 #define check_arg_timer(timer)	do {} while (0)
126 #define check_arg_vec(vec)	do {} while (0)
127 #define check_arg_pri(pri)	do {} while (0)
128 #define check_arg_irq(irq)	do {} while (0)
129 #define check_arg_cpu(cpu)	do {} while (0)
130 #endif
131 
132 #define GET_ISU(source)	ISU[(source) >> 4][(source) & 0xf]
133 
134 void
openpic_init_irq_desc(irq_desc_t * desc)135 openpic_init_irq_desc(irq_desc_t *desc)
136 {
137 	/* Don't mess with the handler if already set.
138 	 * This leaves the setup of isa/ipi handlers undisturbed.
139 	 */
140 	if (!desc->handler)
141 		desc->handler = &open_pic;
142 }
143 
openpic_init_IRQ(void)144 void __init openpic_init_IRQ(void)
145 {
146         struct device_node *np;
147         int i;
148         unsigned int *addrp;
149         unsigned char* chrp_int_ack_special = 0;
150 	unsigned char init_senses[NR_IRQS - NUM_ISA_INTERRUPTS];
151         int nmi_irq = -1;
152 #if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
153         struct device_node *kbd;
154 #endif
155 
156         if (!(np = find_devices("pci"))
157             || !(addrp = (unsigned int *)
158                  get_property(np, "8259-interrupt-acknowledge", NULL)))
159                 printk(KERN_ERR "Cannot find pci to get ack address\n");
160         else
161 		chrp_int_ack_special = (unsigned char *)
162 			__ioremap(addrp[prom_n_addr_cells(np)-1], 1, _PAGE_NO_CACHE);
163         /* hydra still sets OpenPIC_InitSenses to a static set of values */
164         if (OpenPIC_InitSenses == NULL) {
165 		prom_get_irq_senses(init_senses, NUM_ISA_INTERRUPTS, NR_IRQS);
166 		OpenPIC_InitSenses = init_senses;
167 		OpenPIC_NumInitSenses = NR_IRQS - NUM_ISA_INTERRUPTS;
168 	}
169 	openpic_init(1, NUM_ISA_INTERRUPTS, chrp_int_ack_special, nmi_irq);
170 	for ( i = 0 ; i < NUM_ISA_INTERRUPTS  ; i++ )
171 		real_irqdesc(i)->handler = &i8259_pic;
172         i8259_init();
173 }
174 
openpic_read(volatile u_int * addr)175 static inline u_int openpic_read(volatile u_int *addr)
176 {
177 	u_int val;
178 
179 	val = in_le32(addr);
180 	return val;
181 }
182 
openpic_write(volatile u_int * addr,u_int val)183 static inline void openpic_write(volatile u_int *addr, u_int val)
184 {
185 	out_le32(addr, val);
186 }
187 
openpic_readfield(volatile u_int * addr,u_int mask)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 
openpic_writefield(volatile u_int * addr,u_int mask,u_int field)194 static 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 
openpic_clearfield(volatile u_int * addr,u_int mask)201 static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
202 {
203 	openpic_writefield(addr, mask, 0);
204 }
205 
openpic_setfield(volatile u_int * addr,u_int mask)206 static inline void openpic_setfield(volatile u_int *addr, u_int mask)
207 {
208 	openpic_writefield(addr, mask, mask);
209 }
210 
openpic_safe_writefield(volatile u_int * addr,u_int mask,u_int field)211 static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
212 				    u_int field)
213 {
214 	unsigned int loops = 100000;
215 
216 	openpic_setfield(addr, OPENPIC_MASK);
217 	while (openpic_read(addr) & OPENPIC_ACTIVITY) {
218 		if (!loops--) {
219 			printk(KERN_ERR "openpic_safe_writefield timeout\n");
220 			break;
221 		}
222 	}
223 	openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
224 }
225 
226 #ifdef CONFIG_SMP
openpic_read_IPI(volatile u_int * addr)227 static u_int openpic_read_IPI(volatile u_int* addr)
228 {
229         u_int val = 0;
230 
231 	if (broken_ipi_registers)
232 		/* yes this is right ... bug, feature, you decide! -- tgall */
233 		val = in_be32(addr);
234 	else
235 		val = in_le32(addr);
236 
237         return val;
238 }
239 
openpic_test_broken_IPI(void)240 static void openpic_test_broken_IPI(void)
241 {
242 	u_int t;
243 
244 	openpic_write(&OpenPIC->Global.IPI_Vector_Priority(0), OPENPIC_MASK);
245 	t = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(0));
246 	if (t == le32_to_cpu(OPENPIC_MASK)) {
247 		printk(KERN_INFO "OpenPIC reversed IPI registers detected\n");
248 		broken_ipi_registers = 1;
249 	}
250 }
251 
252 /* because of the power3 be / le above, this is needed */
openpic_writefield_IPI(volatile u_int * addr,u_int mask,u_int field)253 static inline void openpic_writefield_IPI(volatile u_int* addr, u_int mask, u_int field)
254 {
255         u_int  val = openpic_read_IPI(addr);
256         openpic_write(addr, (val & ~mask) | (field & mask));
257 }
258 
openpic_clearfield_IPI(volatile u_int * addr,u_int mask)259 static inline void openpic_clearfield_IPI(volatile u_int *addr, u_int mask)
260 {
261         openpic_writefield_IPI(addr, mask, 0);
262 }
263 
openpic_setfield_IPI(volatile u_int * addr,u_int mask)264 static inline void openpic_setfield_IPI(volatile u_int *addr, u_int mask)
265 {
266         openpic_writefield_IPI(addr, mask, mask);
267 }
268 
openpic_safe_writefield_IPI(volatile u_int * addr,u_int mask,u_int field)269 static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int field)
270 {
271 	unsigned int loops = 100000;
272 
273         openpic_setfield_IPI(addr, OPENPIC_MASK);
274 
275         /* wait until it's not in use */
276         /* BenH: Is this code really enough ? I would rather check the result
277          *       and eventually retry ...
278          */
279         while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY) {
280 		if (!loops--) {
281 			printk(KERN_ERR "openpic_safe_writefield timeout\n");
282 			break;
283 		}
284 	}
285 
286         openpic_writefield_IPI(addr, mask, field | OPENPIC_MASK);
287 }
288 #endif /* CONFIG_SMP */
289 
openpic_init(int main_pic,int offset,unsigned char * chrp_ack,int programmer_switch_irq)290 void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
291 			 int programmer_switch_irq)
292 {
293 	u_int t, i;
294 	u_int timerfreq;
295 	const char *version;
296 
297 	if (!OpenPIC_Addr) {
298 		printk(KERN_INFO "No OpenPIC found !\n");
299 		return;
300 	}
301 	OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
302 
303 	ppc64_boot_msg(0x20, "OpenPic Init");
304 
305 	t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
306 	switch (t & OPENPIC_FEATURE_VERSION_MASK) {
307 	case 1:
308 		version = "1.0";
309 		break;
310 	case 2:
311 		version = "1.2";
312 		break;
313 	case 3:
314 		version = "1.3";
315 		break;
316 	default:
317 		version = "?";
318 		break;
319 	}
320 	NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
321 			 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
322 	NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
323 		      OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
324 	printk(KERN_INFO "OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n",
325 	       version, NumProcessors, NumSources, OpenPIC);
326 	timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
327 	if (timerfreq)
328 		printk(KERN_INFO "OpenPIC timer frequency is %d.%06d MHz\n",
329 		       timerfreq / 1000000, timerfreq % 1000000);
330 
331 	if (!main_pic)
332 		return;
333 
334 	open_pic_irq_offset = offset;
335 	chrp_int_ack_special = (volatile unsigned char*)chrp_ack;
336 
337 	find_ISUs();
338 
339 	/* Initialize timer interrupts */
340 	ppc64_boot_msg(0x21, "OpenPic Timer");
341 	for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
342 		/* Disabled, Priority 0 */
343 		openpic_inittimer(i, 0, openpic_vec_timer+i);
344 		/* No processor */
345 		openpic_maptimer(i, 0);
346 	}
347 
348 #ifdef CONFIG_SMP
349 	/* Initialize IPI interrupts */
350 	ppc64_boot_msg(0x22, "OpenPic IPI");
351 	openpic_test_broken_IPI();
352 	for (i = 0; i < OPENPIC_NUM_IPI; i++) {
353 		/* Disabled, Priority 10..13 */
354 		openpic_initipi(i, 10+i, openpic_vec_ipi+i);
355 		/* IPIs are per-CPU */
356 		real_irqdesc(openpic_vec_ipi+i)->status |= IRQ_PER_CPU;
357 		real_irqdesc(openpic_vec_ipi+i)->handler = &open_pic_ipi;
358 	}
359 #endif
360 
361 	/* Initialize external interrupts */
362 	ppc64_boot_msg(0x23, "OpenPic Ext");
363 
364 	openpic_set_priority(0xf);
365 
366 	/* SIOint (8259 cascade) is special */
367 	if (offset) {
368 		openpic_initirq(0, 8, offset, 1, 1);
369 		openpic_mapirq(0, 1<<get_hard_smp_processor_id(0));
370 	}
371 
372 	/* Init all external sources */
373 	for (i = 1; i < NumSources; i++) {
374 		int pri, sense;
375 
376 		/* the bootloader may have left it enabled (bad !) */
377 		openpic_disable_irq(i+offset);
378 
379 		pri = (i == programmer_switch_irq)? 9: 8;
380 		sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
381 		if (sense)
382 			real_irqdesc(i+offset)->status = IRQ_LEVEL;
383 
384 		/* Enabled, Priority 8 or 9 */
385 		openpic_initirq(i, pri, i+offset, !sense, sense);
386 		/* Processor 0 */
387 		openpic_mapirq(i, 1<<get_hard_smp_processor_id(0));
388 	}
389 
390 	/* Initialize the spurious interrupt */
391 	ppc64_boot_msg(0x24, "OpenPic Spurious");
392 	openpic_set_spurious(openpic_vec_spurious);
393 
394 	/* Initialize the cascade */
395 	if (offset) {
396 		if (request_irq(offset, no_action, SA_INTERRUPT,
397 				"82c59 cascade", NULL))
398 			printk(KERN_ERR "Unable to get OpenPIC IRQ 0 for cascade\n");
399 	}
400 	openpic_set_priority(0);
401 	openpic_disable_8259_pass_through();
402 
403 	ppc64_boot_msg(0x25, "OpenPic Done");
404 }
405 
openpic_setup_ISU(int isu_num,unsigned long addr)406 void openpic_setup_ISU(int isu_num, unsigned long addr)
407 {
408 	if (isu_num >= OPENPIC_MAX_ISU)
409 		return;
410 	ISU[isu_num] = (OpenPIC_SourcePtr) __ioremap(addr, 0x400, _PAGE_NO_CACHE);
411 	if (isu_num >= NumISUs)
412 		NumISUs = isu_num + 1;
413 }
414 
find_ISUs(void)415 void find_ISUs(void)
416 {
417         /* Use /interrupt-controller/reg and
418          * /interrupt-controller/interrupt-ranges from OF device tree
419 	 * the ISU array is setup in chrp_pci.c in ibm_add_bridges
420 	 * as a result
421 	 * -- tgall
422          */
423 
424 	/* basically each ISU is a bus, and this assumes that
425 	 * open_pic_isu_count interrupts per bus are possible
426 	 * ISU == Interrupt Source
427 	 */
428 	NumSources = NumISUs * 0x10;
429 	openpic_vec_ipi = NumSources + open_pic_irq_offset;
430 	openpic_vec_timer = openpic_vec_ipi + OPENPIC_NUM_IPI;
431 	openpic_vec_spurious = openpic_vec_timer + OPENPIC_NUM_TIMERS;
432 }
433 
openpic_reset(void)434 static inline void openpic_reset(void)
435 {
436 	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
437 			 OPENPIC_CONFIG_RESET);
438 }
439 
openpic_enable_8259_pass_through(void)440 static inline void openpic_enable_8259_pass_through(void)
441 {
442 	openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
443 			   OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
444 }
445 
openpic_disable_8259_pass_through(void)446 static void openpic_disable_8259_pass_through(void)
447 {
448 	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
449 			 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
450 }
451 
452 /*
453  *  Find out the current interrupt
454  */
openpic_irq(void)455 static u_int openpic_irq(void)
456 {
457 	u_int vec;
458 	DECL_THIS_CPU;
459 
460 	CHECK_THIS_CPU;
461 	vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
462 				OPENPIC_VECTOR_MASK);
463 	return vec;
464 }
465 
openpic_eoi(void)466 static void openpic_eoi(void)
467 {
468 	DECL_THIS_CPU;
469 
470 	CHECK_THIS_CPU;
471 	openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
472 	/* Handle PCI write posting */
473 	(void)openpic_read(&OpenPIC->THIS_CPU.EOI);
474 }
475 
476 
openpic_get_priority(void)477 static inline u_int openpic_get_priority(void)
478 {
479 	DECL_THIS_CPU;
480 
481 	CHECK_THIS_CPU;
482 	return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
483 				 OPENPIC_CURRENT_TASK_PRIORITY_MASK);
484 }
485 
openpic_set_priority(u_int pri)486 static void openpic_set_priority(u_int pri)
487 {
488 	DECL_THIS_CPU;
489 
490 	CHECK_THIS_CPU;
491 	check_arg_pri(pri);
492 	openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
493 			   OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
494 }
495 
496 /*
497  *  Get/set the spurious vector
498  */
openpic_get_spurious(void)499 static inline u_int openpic_get_spurious(void)
500 {
501 	return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
502 				 OPENPIC_VECTOR_MASK);
503 }
504 
openpic_set_spurious(u_int vec)505 static void openpic_set_spurious(u_int vec)
506 {
507 	check_arg_vec(vec);
508 	openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
509 			   vec);
510 }
511 
512 /*
513  * Convert a cpu mask from logical to physical cpu numbers.
514  */
physmask(u32 cpumask)515 static inline u32 physmask(u32 cpumask)
516 {
517 	int i;
518 	u32 mask = 0;
519 
520 	for (i = 0; i < smp_num_cpus; ++i, cpumask >>= 1)
521 		mask |= (cpumask & 1) << get_hard_smp_processor_id(i);
522 	return mask;
523 }
524 
openpic_init_processor(u_int cpumask)525 void openpic_init_processor(u_int cpumask)
526 {
527 	openpic_write(&OpenPIC->Global.Processor_Initialization,
528 		      physmask(cpumask));
529 }
530 
531 #ifdef CONFIG_SMP
532 /*
533  *  Initialize an interprocessor interrupt (and disable it)
534  *
535  *  ipi: OpenPIC interprocessor interrupt number
536  *  pri: interrupt source priority
537  *  vec: the vector it will produce
538  */
openpic_initipi(u_int ipi,u_int pri,u_int vec)539 static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec)
540 {
541 	check_arg_ipi(ipi);
542 	check_arg_pri(pri);
543 	check_arg_vec(vec);
544 	openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi),
545 				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
546 				(pri << OPENPIC_PRIORITY_SHIFT) | vec);
547 }
548 
549 /*
550  *  Send an IPI to one or more CPUs
551  *
552  *  Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
553  *  and not a system-wide interrupt number
554  */
openpic_cause_IPI(u_int ipi,u_int cpumask)555 void openpic_cause_IPI(u_int ipi, u_int cpumask)
556 {
557 	DECL_THIS_CPU;
558 
559 	CHECK_THIS_CPU;
560 	check_arg_ipi(ipi);
561 	openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
562 		      physmask(cpumask));
563 }
564 
openpic_request_IPIs(void)565 void openpic_request_IPIs(void)
566 {
567 	int i;
568 
569 	/*
570 	 * Make sure this matches what is defined in smp.c for
571 	 * smp_message_{pass|recv}() or what shows up in
572 	 * /proc/interrupts will be wrong!!! --Troy */
573 
574 	if (OpenPIC == NULL)
575 		return;
576 
577 	request_irq(openpic_vec_ipi,
578 		    openpic_ipi_action, 0, "IPI0 (call function)", 0);
579 	request_irq(openpic_vec_ipi+1,
580 		    openpic_ipi_action, 0, "IPI1 (reschedule)", 0);
581 	request_irq(openpic_vec_ipi+2,
582 		    openpic_ipi_action, 0, "IPI2 (invalidate tlb)", 0);
583 	request_irq(openpic_vec_ipi+3,
584 		    openpic_ipi_action, 0, "IPI3 (xmon break)", 0);
585 
586 	for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
587 		openpic_enable_ipi(openpic_vec_ipi+i);
588 }
589 
590 /*
591  * Do per-cpu setup for SMP systems.
592  *
593  * Get IPI's working and start taking interrupts.
594  *   -- Cort
595  */
596 static spinlock_t openpic_setup_lock __initdata = SPIN_LOCK_UNLOCKED;
597 
do_openpic_setup_cpu(void)598 void __init do_openpic_setup_cpu(void)
599 {
600 #ifdef CONFIG_IRQ_ALL_CPUS
601  	int i;
602 	u32 msk = 1 << hard_smp_processor_id();
603 #endif
604 
605 	spin_lock(&openpic_setup_lock);
606 
607 #ifdef CONFIG_IRQ_ALL_CPUS
608  	/* let the openpic know we want intrs. default affinity
609  	 * is 0xffffffff until changed via /proc
610  	 * That's how it's done on x86. If we want it differently, then
611  	 * we should make sure we also change the default values of irq_affinity
612  	 * in irq.c.
613  	 */
614  	for (i = 0; i < NumSources ; i++)
615 		openpic_mapirq(i, openpic_read(&GET_ISU(i).Destination) | msk);
616 #endif /* CONFIG_IRQ_ALL_CPUS */
617  	openpic_set_priority(0);
618 
619 	spin_unlock(&openpic_setup_lock);
620 }
621 #endif /* CONFIG_SMP */
622 
623 /*
624  *  Initialize a timer interrupt (and disable it)
625  *
626  *  timer: OpenPIC timer number
627  *  pri: interrupt source priority
628  *  vec: the vector it will produce
629  */
openpic_inittimer(u_int timer,u_int pri,u_int vec)630 static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec)
631 {
632 	check_arg_timer(timer);
633 	check_arg_pri(pri);
634 	check_arg_vec(vec);
635 	openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
636 				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
637 				(pri << OPENPIC_PRIORITY_SHIFT) | vec);
638 }
639 
640 /*
641  *  Map a timer interrupt to one or more CPUs
642  */
openpic_maptimer(u_int timer,u_int cpumask)643 static void __init openpic_maptimer(u_int timer, u_int cpumask)
644 {
645 	check_arg_timer(timer);
646 	openpic_write(&OpenPIC->Global.Timer[timer].Destination,
647 		      physmask(cpumask));
648 }
649 
650 
651 /*
652  *
653  * All functions below take an offset'ed irq argument
654  *
655  */
656 
657 
658 /*
659  *  Enable/disable an external interrupt source
660  *
661  *  Externally called, irq is an offseted system-wide interrupt number
662  */
openpic_enable_irq(u_int irq)663 static void openpic_enable_irq(u_int irq)
664 {
665 	unsigned int loops = 100000;
666 	check_arg_irq(irq);
667 
668 	openpic_clearfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
669 	/* make sure mask gets to controller before we return to user */
670 	do {
671 		if (!loops--) {
672 			printk(KERN_ERR "openpic_enable_irq timeout\n");
673 			break;
674 		}
675 
676 		mb(); /* sync is probably useless here */
677 	} while(openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
678 			OPENPIC_MASK));
679 }
680 
openpic_disable_irq(u_int irq)681 static void openpic_disable_irq(u_int irq)
682 {
683 	u32 vp;
684 	unsigned int loops = 100000;
685 
686 	check_arg_irq(irq);
687 
688 	openpic_setfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
689 	/* make sure mask gets to controller before we return to user */
690 	do {
691 		if (!loops--) {
692 			printk(KERN_ERR "openpic_disable_irq timeout\n");
693 			break;
694 		}
695 
696 		mb();  /* sync is probably useless here */
697 		vp = openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
698     			OPENPIC_MASK | OPENPIC_ACTIVITY);
699 	} while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
700 }
701 
702 #ifdef CONFIG_SMP
703 /*
704  *  Enable/disable an IPI interrupt source
705  *
706  *  Externally called, irq is an offseted system-wide interrupt number
707  */
openpic_enable_ipi(u_int irq)708 void openpic_enable_ipi(u_int irq)
709 {
710 	irq -= openpic_vec_ipi;
711 	check_arg_ipi(irq);
712 	openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
713 
714 }
openpic_disable_ipi(u_int irq)715 void openpic_disable_ipi(u_int irq)
716 {
717    /* NEVER disable an IPI... that's just plain wrong! */
718 }
719 
720 #endif
721 
722 /*
723  *  Initialize an interrupt source (and disable it!)
724  *
725  *  irq: OpenPIC interrupt number
726  *  pri: interrupt source priority
727  *  vec: the vector it will produce
728  *  pol: polarity (1 for positive, 0 for negative)
729  *  sense: 1 for level, 0 for edge
730  */
openpic_initirq(u_int irq,u_int pri,u_int vec,int pol,int sense)731 static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
732 {
733 	openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
734 				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
735 				OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
736 				(pri << OPENPIC_PRIORITY_SHIFT) | vec |
737 				(pol ? OPENPIC_POLARITY_POSITIVE :
738 			    		OPENPIC_POLARITY_NEGATIVE) |
739 				(sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
740 }
741 
742 /*
743  *  Map an interrupt source to one or more CPUs
744  */
openpic_mapirq(u_int irq,u_int physmask)745 static void openpic_mapirq(u_int irq, u_int physmask)
746 {
747 	openpic_write(&GET_ISU(irq).Destination, physmask);
748 }
749 
750 /*
751  *  Set the sense for an interrupt source (and disable it!)
752  *
753  *  sense: 1 for level, 0 for edge
754  */
openpic_set_sense(u_int irq,int sense)755 static inline void openpic_set_sense(u_int irq, int sense)
756 {
757 	openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
758 				OPENPIC_SENSE_LEVEL,
759 				(sense ? OPENPIC_SENSE_LEVEL : 0));
760 }
761 
openpic_end_irq(unsigned int irq_nr)762 static void openpic_end_irq(unsigned int irq_nr)
763 {
764 	if ((irqdesc(irq_nr)->status & IRQ_LEVEL) != 0)
765 		openpic_eoi();
766 }
767 
openpic_set_affinity(unsigned int irq_nr,unsigned long cpumask)768 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
769 {
770 	openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask));
771 }
772 
773 #ifdef CONFIG_SMP
openpic_end_ipi(unsigned int irq_nr)774 static void openpic_end_ipi(unsigned int irq_nr)
775 {
776 	/* IPIs are marked IRQ_PER_CPU. This has the side effect of
777 	 * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from
778 	 * applying to them. We EOI them late to avoid re-entering.
779 	 * however, I'm wondering if we could simply let them have the
780 	 * SA_INTERRUPT flag and let them execute with all interrupts OFF.
781 	 * This would have the side effect of either running cross-CPU
782 	 * functions with interrupts off, or we can re-enable them explicitely
783 	 * with a __sti() in smp_call_function_interrupt(), since
784 	 * smp_call_function() is protected by a spinlock.
785 	 * Or maybe we shouldn't set the IRQ_PER_CPU flag on cross-CPU
786 	 * function calls IPI at all but that would make a special case.
787 	 */
788 	openpic_eoi();
789 }
790 
openpic_ipi_action(int cpl,void * dev_id,struct pt_regs * regs)791 static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
792 {
793 	smp_message_recv(cpl-openpic_vec_ipi, regs);
794 }
795 
796 #endif /* CONFIG_SMP */
797 
openpic_get_irq(struct pt_regs * regs)798 int openpic_get_irq(struct pt_regs *regs)
799 {
800 	extern int i8259_irq(int cpu);
801 
802 	int irq = openpic_irq();
803 
804 	/* Management of the cascade should be moved out of here */
805         if (open_pic_irq_offset && irq == open_pic_irq_offset)
806         {
807                 /*
808                  * This magic address generates a PCI IACK cycle.
809                  */
810 		if ( chrp_int_ack_special )
811 			irq = *chrp_int_ack_special;
812 		else
813 			irq = i8259_irq( smp_processor_id() );
814 		openpic_eoi();
815         }
816 	if (irq == openpic_vec_spurious)
817 		irq = -1;
818 	return irq;
819 }
820