Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (C) 2003 Ralf Baechle | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of the GNU General Public License as published by the | |
6 | * Free Software Foundation; either version 2 of the License, or (at your | |
7 | * option) any later version. | |
8 | * | |
9 | * Handler for RM9000 extended interrupts. These are a non-standard | |
10 | * feature so we handle them separately from standard interrupts. | |
11 | */ | |
12 | #include <linux/init.h> | |
13 | #include <linux/interrupt.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/module.h> | |
16 | ||
17 | #include <asm/irq_cpu.h> | |
18 | #include <asm/mipsregs.h> | |
19 | #include <asm/system.h> | |
20 | ||
21 | static int irq_base; | |
22 | ||
23 | static inline void unmask_rm9k_irq(unsigned int irq) | |
24 | { | |
25 | set_c0_intcontrol(0x1000 << (irq - irq_base)); | |
26 | } | |
27 | ||
28 | static inline void mask_rm9k_irq(unsigned int irq) | |
29 | { | |
30 | clear_c0_intcontrol(0x1000 << (irq - irq_base)); | |
31 | } | |
32 | ||
33 | static inline void rm9k_cpu_irq_enable(unsigned int irq) | |
34 | { | |
35 | unsigned long flags; | |
36 | ||
37 | local_irq_save(flags); | |
38 | unmask_rm9k_irq(irq); | |
39 | local_irq_restore(flags); | |
40 | } | |
41 | ||
42 | static void rm9k_cpu_irq_disable(unsigned int irq) | |
43 | { | |
44 | unsigned long flags; | |
45 | ||
46 | local_irq_save(flags); | |
47 | mask_rm9k_irq(irq); | |
48 | local_irq_restore(flags); | |
49 | } | |
50 | ||
1da177e4 LT |
51 | /* |
52 | * Performance counter interrupts are global on all processors. | |
53 | */ | |
54 | static void local_rm9k_perfcounter_irq_startup(void *args) | |
55 | { | |
56 | unsigned int irq = (unsigned int) args; | |
57 | ||
58 | rm9k_cpu_irq_enable(irq); | |
59 | } | |
60 | ||
61 | static unsigned int rm9k_perfcounter_irq_startup(unsigned int irq) | |
62 | { | |
63 | on_each_cpu(local_rm9k_perfcounter_irq_startup, (void *) irq, 0, 1); | |
64 | ||
65 | return 0; | |
66 | } | |
67 | ||
68 | static void local_rm9k_perfcounter_irq_shutdown(void *args) | |
69 | { | |
70 | unsigned int irq = (unsigned int) args; | |
71 | unsigned long flags; | |
72 | ||
73 | local_irq_save(flags); | |
74 | mask_rm9k_irq(irq); | |
75 | local_irq_restore(flags); | |
76 | } | |
77 | ||
78 | static void rm9k_perfcounter_irq_shutdown(unsigned int irq) | |
79 | { | |
80 | on_each_cpu(local_rm9k_perfcounter_irq_shutdown, (void *) irq, 0, 1); | |
81 | } | |
82 | ||
1da177e4 LT |
83 | static void rm9k_cpu_irq_end(unsigned int irq) |
84 | { | |
85 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | |
86 | unmask_rm9k_irq(irq); | |
87 | } | |
88 | ||
94dee171 | 89 | static struct irq_chip rm9k_irq_controller = { |
8ab00b9a | 90 | .typename = "RM9000", |
1603b5ac AN |
91 | .ack = mask_rm9k_irq, |
92 | .mask = mask_rm9k_irq, | |
93 | .mask_ack = mask_rm9k_irq, | |
94 | .unmask = unmask_rm9k_irq, | |
8ab00b9a | 95 | .end = rm9k_cpu_irq_end, |
1da177e4 LT |
96 | }; |
97 | ||
94dee171 | 98 | static struct irq_chip rm9k_perfcounter_irq = { |
8ab00b9a RB |
99 | .typename = "RM9000", |
100 | .startup = rm9k_perfcounter_irq_startup, | |
101 | .shutdown = rm9k_perfcounter_irq_shutdown, | |
1603b5ac AN |
102 | .ack = mask_rm9k_irq, |
103 | .mask = mask_rm9k_irq, | |
104 | .mask_ack = mask_rm9k_irq, | |
105 | .unmask = unmask_rm9k_irq, | |
8ab00b9a | 106 | .end = rm9k_cpu_irq_end, |
1da177e4 LT |
107 | }; |
108 | ||
109 | unsigned int rm9000_perfcount_irq; | |
110 | ||
111 | EXPORT_SYMBOL(rm9000_perfcount_irq); | |
112 | ||
113 | void __init rm9k_cpu_irq_init(int base) | |
114 | { | |
115 | int i; | |
116 | ||
117 | clear_c0_intcontrol(0x0000f000); /* Mask all */ | |
118 | ||
1603b5ac | 119 | for (i = base; i < base + 4; i++) |
1417836e AN |
120 | set_irq_chip_and_handler(i, &rm9k_irq_controller, |
121 | handle_level_irq); | |
1da177e4 LT |
122 | |
123 | rm9000_perfcount_irq = base + 1; | |
1417836e AN |
124 | set_irq_chip_and_handler(rm9000_perfcount_irq, &rm9k_perfcounter_irq, |
125 | handle_level_irq); | |
1da177e4 LT |
126 | |
127 | irq_base = base; | |
128 | } |