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