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