diff options
Diffstat (limited to 'arch/mips/bcm63xx/irq.c')
-rw-r--r-- | arch/mips/bcm63xx/irq.c | 558 |
1 files changed, 269 insertions, 289 deletions
diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c index 1525f8a3841b..37eb2d1fa69a 100644 --- a/arch/mips/bcm63xx/irq.c +++ b/arch/mips/bcm63xx/irq.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
15 | #include <linux/spinlock.h> | ||
15 | #include <asm/irq_cpu.h> | 16 | #include <asm/irq_cpu.h> |
16 | #include <asm/mipsregs.h> | 17 | #include <asm/mipsregs.h> |
17 | #include <bcm63xx_cpu.h> | 18 | #include <bcm63xx_cpu.h> |
@@ -19,222 +20,20 @@ | |||
19 | #include <bcm63xx_io.h> | 20 | #include <bcm63xx_io.h> |
20 | #include <bcm63xx_irq.h> | 21 | #include <bcm63xx_irq.h> |
21 | 22 | ||
22 | static void __dispatch_internal(void) __maybe_unused; | ||
23 | static void __dispatch_internal_64(void) __maybe_unused; | ||
24 | static void __internal_irq_mask_32(unsigned int irq) __maybe_unused; | ||
25 | static void __internal_irq_mask_64(unsigned int irq) __maybe_unused; | ||
26 | static void __internal_irq_unmask_32(unsigned int irq) __maybe_unused; | ||
27 | static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused; | ||
28 | |||
29 | #ifndef BCMCPU_RUNTIME_DETECT | ||
30 | #ifdef CONFIG_BCM63XX_CPU_3368 | ||
31 | #define irq_stat_reg PERF_IRQSTAT_3368_REG | ||
32 | #define irq_mask_reg PERF_IRQMASK_3368_REG | ||
33 | #define irq_bits 32 | ||
34 | #define is_ext_irq_cascaded 0 | ||
35 | #define ext_irq_start 0 | ||
36 | #define ext_irq_end 0 | ||
37 | #define ext_irq_count 4 | ||
38 | #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_3368 | ||
39 | #define ext_irq_cfg_reg2 0 | ||
40 | #endif | ||
41 | #ifdef CONFIG_BCM63XX_CPU_6328 | ||
42 | #define irq_stat_reg PERF_IRQSTAT_6328_REG | ||
43 | #define irq_mask_reg PERF_IRQMASK_6328_REG | ||
44 | #define irq_bits 64 | ||
45 | #define is_ext_irq_cascaded 1 | ||
46 | #define ext_irq_start (BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE) | ||
47 | #define ext_irq_end (BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE) | ||
48 | #define ext_irq_count 4 | ||
49 | #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6328 | ||
50 | #define ext_irq_cfg_reg2 0 | ||
51 | #endif | ||
52 | #ifdef CONFIG_BCM63XX_CPU_6338 | ||
53 | #define irq_stat_reg PERF_IRQSTAT_6338_REG | ||
54 | #define irq_mask_reg PERF_IRQMASK_6338_REG | ||
55 | #define irq_bits 32 | ||
56 | #define is_ext_irq_cascaded 0 | ||
57 | #define ext_irq_start 0 | ||
58 | #define ext_irq_end 0 | ||
59 | #define ext_irq_count 4 | ||
60 | #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6338 | ||
61 | #define ext_irq_cfg_reg2 0 | ||
62 | #endif | ||
63 | #ifdef CONFIG_BCM63XX_CPU_6345 | ||
64 | #define irq_stat_reg PERF_IRQSTAT_6345_REG | ||
65 | #define irq_mask_reg PERF_IRQMASK_6345_REG | ||
66 | #define irq_bits 32 | ||
67 | #define is_ext_irq_cascaded 0 | ||
68 | #define ext_irq_start 0 | ||
69 | #define ext_irq_end 0 | ||
70 | #define ext_irq_count 4 | ||
71 | #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6345 | ||
72 | #define ext_irq_cfg_reg2 0 | ||
73 | #endif | ||
74 | #ifdef CONFIG_BCM63XX_CPU_6348 | ||
75 | #define irq_stat_reg PERF_IRQSTAT_6348_REG | ||
76 | #define irq_mask_reg PERF_IRQMASK_6348_REG | ||
77 | #define irq_bits 32 | ||
78 | #define is_ext_irq_cascaded 0 | ||
79 | #define ext_irq_start 0 | ||
80 | #define ext_irq_end 0 | ||
81 | #define ext_irq_count 4 | ||
82 | #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6348 | ||
83 | #define ext_irq_cfg_reg2 0 | ||
84 | #endif | ||
85 | #ifdef CONFIG_BCM63XX_CPU_6358 | ||
86 | #define irq_stat_reg PERF_IRQSTAT_6358_REG | ||
87 | #define irq_mask_reg PERF_IRQMASK_6358_REG | ||
88 | #define irq_bits 32 | ||
89 | #define is_ext_irq_cascaded 1 | ||
90 | #define ext_irq_start (BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE) | ||
91 | #define ext_irq_end (BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE) | ||
92 | #define ext_irq_count 4 | ||
93 | #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6358 | ||
94 | #define ext_irq_cfg_reg2 0 | ||
95 | #endif | ||
96 | #ifdef CONFIG_BCM63XX_CPU_6362 | ||
97 | #define irq_stat_reg PERF_IRQSTAT_6362_REG | ||
98 | #define irq_mask_reg PERF_IRQMASK_6362_REG | ||
99 | #define irq_bits 64 | ||
100 | #define is_ext_irq_cascaded 1 | ||
101 | #define ext_irq_start (BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE) | ||
102 | #define ext_irq_end (BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE) | ||
103 | #define ext_irq_count 4 | ||
104 | #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6362 | ||
105 | #define ext_irq_cfg_reg2 0 | ||
106 | #endif | ||
107 | #ifdef CONFIG_BCM63XX_CPU_6368 | ||
108 | #define irq_stat_reg PERF_IRQSTAT_6368_REG | ||
109 | #define irq_mask_reg PERF_IRQMASK_6368_REG | ||
110 | #define irq_bits 64 | ||
111 | #define is_ext_irq_cascaded 1 | ||
112 | #define ext_irq_start (BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE) | ||
113 | #define ext_irq_end (BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE) | ||
114 | #define ext_irq_count 6 | ||
115 | #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6368 | ||
116 | #define ext_irq_cfg_reg2 PERF_EXTIRQ_CFG_REG2_6368 | ||
117 | #endif | ||
118 | |||
119 | #if irq_bits == 32 | ||
120 | #define dispatch_internal __dispatch_internal | ||
121 | #define internal_irq_mask __internal_irq_mask_32 | ||
122 | #define internal_irq_unmask __internal_irq_unmask_32 | ||
123 | #else | ||
124 | #define dispatch_internal __dispatch_internal_64 | ||
125 | #define internal_irq_mask __internal_irq_mask_64 | ||
126 | #define internal_irq_unmask __internal_irq_unmask_64 | ||
127 | #endif | ||
128 | 23 | ||
129 | #define irq_stat_addr (bcm63xx_regset_address(RSET_PERF) + irq_stat_reg) | 24 | static DEFINE_SPINLOCK(ipic_lock); |
130 | #define irq_mask_addr (bcm63xx_regset_address(RSET_PERF) + irq_mask_reg) | 25 | static DEFINE_SPINLOCK(epic_lock); |
131 | 26 | ||
132 | static inline void bcm63xx_init_irq(void) | 27 | static u32 irq_stat_addr[2]; |
133 | { | 28 | static u32 irq_mask_addr[2]; |
134 | } | 29 | static void (*dispatch_internal)(int cpu); |
135 | #else /* ! BCMCPU_RUNTIME_DETECT */ | ||
136 | |||
137 | static u32 irq_stat_addr, irq_mask_addr; | ||
138 | static void (*dispatch_internal)(void); | ||
139 | static int is_ext_irq_cascaded; | 30 | static int is_ext_irq_cascaded; |
140 | static unsigned int ext_irq_count; | 31 | static unsigned int ext_irq_count; |
141 | static unsigned int ext_irq_start, ext_irq_end; | 32 | static unsigned int ext_irq_start, ext_irq_end; |
142 | static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2; | 33 | static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2; |
143 | static void (*internal_irq_mask)(unsigned int irq); | 34 | static void (*internal_irq_mask)(struct irq_data *d); |
144 | static void (*internal_irq_unmask)(unsigned int irq); | 35 | static void (*internal_irq_unmask)(struct irq_data *d, const struct cpumask *m); |
145 | 36 | ||
146 | static void bcm63xx_init_irq(void) | ||
147 | { | ||
148 | int irq_bits; | ||
149 | |||
150 | irq_stat_addr = bcm63xx_regset_address(RSET_PERF); | ||
151 | irq_mask_addr = bcm63xx_regset_address(RSET_PERF); | ||
152 | |||
153 | switch (bcm63xx_get_cpu_id()) { | ||
154 | case BCM3368_CPU_ID: | ||
155 | irq_stat_addr += PERF_IRQSTAT_3368_REG; | ||
156 | irq_mask_addr += PERF_IRQMASK_3368_REG; | ||
157 | irq_bits = 32; | ||
158 | ext_irq_count = 4; | ||
159 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368; | ||
160 | break; | ||
161 | case BCM6328_CPU_ID: | ||
162 | irq_stat_addr += PERF_IRQSTAT_6328_REG; | ||
163 | irq_mask_addr += PERF_IRQMASK_6328_REG; | ||
164 | irq_bits = 64; | ||
165 | ext_irq_count = 4; | ||
166 | is_ext_irq_cascaded = 1; | ||
167 | ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE; | ||
168 | ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE; | ||
169 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328; | ||
170 | break; | ||
171 | case BCM6338_CPU_ID: | ||
172 | irq_stat_addr += PERF_IRQSTAT_6338_REG; | ||
173 | irq_mask_addr += PERF_IRQMASK_6338_REG; | ||
174 | irq_bits = 32; | ||
175 | ext_irq_count = 4; | ||
176 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338; | ||
177 | break; | ||
178 | case BCM6345_CPU_ID: | ||
179 | irq_stat_addr += PERF_IRQSTAT_6345_REG; | ||
180 | irq_mask_addr += PERF_IRQMASK_6345_REG; | ||
181 | irq_bits = 32; | ||
182 | ext_irq_count = 4; | ||
183 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345; | ||
184 | break; | ||
185 | case BCM6348_CPU_ID: | ||
186 | irq_stat_addr += PERF_IRQSTAT_6348_REG; | ||
187 | irq_mask_addr += PERF_IRQMASK_6348_REG; | ||
188 | irq_bits = 32; | ||
189 | ext_irq_count = 4; | ||
190 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348; | ||
191 | break; | ||
192 | case BCM6358_CPU_ID: | ||
193 | irq_stat_addr += PERF_IRQSTAT_6358_REG; | ||
194 | irq_mask_addr += PERF_IRQMASK_6358_REG; | ||
195 | irq_bits = 32; | ||
196 | ext_irq_count = 4; | ||
197 | is_ext_irq_cascaded = 1; | ||
198 | ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE; | ||
199 | ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE; | ||
200 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358; | ||
201 | break; | ||
202 | case BCM6362_CPU_ID: | ||
203 | irq_stat_addr += PERF_IRQSTAT_6362_REG; | ||
204 | irq_mask_addr += PERF_IRQMASK_6362_REG; | ||
205 | irq_bits = 64; | ||
206 | ext_irq_count = 4; | ||
207 | is_ext_irq_cascaded = 1; | ||
208 | ext_irq_start = BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE; | ||
209 | ext_irq_end = BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE; | ||
210 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6362; | ||
211 | break; | ||
212 | case BCM6368_CPU_ID: | ||
213 | irq_stat_addr += PERF_IRQSTAT_6368_REG; | ||
214 | irq_mask_addr += PERF_IRQMASK_6368_REG; | ||
215 | irq_bits = 64; | ||
216 | ext_irq_count = 6; | ||
217 | is_ext_irq_cascaded = 1; | ||
218 | ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE; | ||
219 | ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE; | ||
220 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368; | ||
221 | ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368; | ||
222 | break; | ||
223 | default: | ||
224 | BUG(); | ||
225 | } | ||
226 | |||
227 | if (irq_bits == 32) { | ||
228 | dispatch_internal = __dispatch_internal; | ||
229 | internal_irq_mask = __internal_irq_mask_32; | ||
230 | internal_irq_unmask = __internal_irq_unmask_32; | ||
231 | } else { | ||
232 | dispatch_internal = __dispatch_internal_64; | ||
233 | internal_irq_mask = __internal_irq_mask_64; | ||
234 | internal_irq_unmask = __internal_irq_unmask_64; | ||
235 | } | ||
236 | } | ||
237 | #endif /* ! BCMCPU_RUNTIME_DETECT */ | ||
238 | 37 | ||
239 | static inline u32 get_ext_irq_perf_reg(int irq) | 38 | static inline u32 get_ext_irq_perf_reg(int irq) |
240 | { | 39 | { |
@@ -252,53 +51,113 @@ static inline void handle_internal(int intbit) | |||
252 | do_IRQ(intbit + IRQ_INTERNAL_BASE); | 51 | do_IRQ(intbit + IRQ_INTERNAL_BASE); |
253 | } | 52 | } |
254 | 53 | ||
54 | static inline int enable_irq_for_cpu(int cpu, struct irq_data *d, | ||
55 | const struct cpumask *m) | ||
56 | { | ||
57 | bool enable = cpu_online(cpu); | ||
58 | |||
59 | #ifdef CONFIG_SMP | ||
60 | if (m) | ||
61 | enable &= cpu_isset(cpu, *m); | ||
62 | else if (irqd_affinity_was_set(d)) | ||
63 | enable &= cpu_isset(cpu, *d->affinity); | ||
64 | #endif | ||
65 | return enable; | ||
66 | } | ||
67 | |||
255 | /* | 68 | /* |
256 | * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not | 69 | * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not |
257 | * prioritize any interrupt relatively to another. the static counter | 70 | * prioritize any interrupt relatively to another. the static counter |
258 | * will resume the loop where it ended the last time we left this | 71 | * will resume the loop where it ended the last time we left this |
259 | * function. | 72 | * function. |
260 | */ | 73 | */ |
261 | static void __dispatch_internal(void) | ||
262 | { | ||
263 | u32 pending; | ||
264 | static int i; | ||
265 | |||
266 | pending = bcm_readl(irq_stat_addr) & bcm_readl(irq_mask_addr); | ||
267 | 74 | ||
268 | if (!pending) | 75 | #define BUILD_IPIC_INTERNAL(width) \ |
269 | return ; | 76 | void __dispatch_internal_##width(int cpu) \ |
270 | 77 | { \ | |
271 | while (1) { | 78 | u32 pending[width / 32]; \ |
272 | int to_call = i; | 79 | unsigned int src, tgt; \ |
273 | 80 | bool irqs_pending = false; \ | |
274 | i = (i + 1) & 0x1f; | 81 | static unsigned int i[2]; \ |
275 | if (pending & (1 << to_call)) { | 82 | unsigned int *next = &i[cpu]; \ |
276 | handle_internal(to_call); | 83 | unsigned long flags; \ |
277 | break; | 84 | \ |
278 | } | 85 | /* read registers in reverse order */ \ |
279 | } | 86 | spin_lock_irqsave(&ipic_lock, flags); \ |
87 | for (src = 0, tgt = (width / 32); src < (width / 32); src++) { \ | ||
88 | u32 val; \ | ||
89 | \ | ||
90 | val = bcm_readl(irq_stat_addr[cpu] + src * sizeof(u32)); \ | ||
91 | val &= bcm_readl(irq_mask_addr[cpu] + src * sizeof(u32)); \ | ||
92 | pending[--tgt] = val; \ | ||
93 | \ | ||
94 | if (val) \ | ||
95 | irqs_pending = true; \ | ||
96 | } \ | ||
97 | spin_unlock_irqrestore(&ipic_lock, flags); \ | ||
98 | \ | ||
99 | if (!irqs_pending) \ | ||
100 | return; \ | ||
101 | \ | ||
102 | while (1) { \ | ||
103 | unsigned int to_call = *next; \ | ||
104 | \ | ||
105 | *next = (*next + 1) & (width - 1); \ | ||
106 | if (pending[to_call / 32] & (1 << (to_call & 0x1f))) { \ | ||
107 | handle_internal(to_call); \ | ||
108 | break; \ | ||
109 | } \ | ||
110 | } \ | ||
111 | } \ | ||
112 | \ | ||
113 | static void __internal_irq_mask_##width(struct irq_data *d) \ | ||
114 | { \ | ||
115 | u32 val; \ | ||
116 | unsigned irq = d->irq - IRQ_INTERNAL_BASE; \ | ||
117 | unsigned reg = (irq / 32) ^ (width/32 - 1); \ | ||
118 | unsigned bit = irq & 0x1f; \ | ||
119 | unsigned long flags; \ | ||
120 | int cpu; \ | ||
121 | \ | ||
122 | spin_lock_irqsave(&ipic_lock, flags); \ | ||
123 | for_each_present_cpu(cpu) { \ | ||
124 | if (!irq_mask_addr[cpu]) \ | ||
125 | break; \ | ||
126 | \ | ||
127 | val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\ | ||
128 | val &= ~(1 << bit); \ | ||
129 | bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\ | ||
130 | } \ | ||
131 | spin_unlock_irqrestore(&ipic_lock, flags); \ | ||
132 | } \ | ||
133 | \ | ||
134 | static void __internal_irq_unmask_##width(struct irq_data *d, \ | ||
135 | const struct cpumask *m) \ | ||
136 | { \ | ||
137 | u32 val; \ | ||
138 | unsigned irq = d->irq - IRQ_INTERNAL_BASE; \ | ||
139 | unsigned reg = (irq / 32) ^ (width/32 - 1); \ | ||
140 | unsigned bit = irq & 0x1f; \ | ||
141 | unsigned long flags; \ | ||
142 | int cpu; \ | ||
143 | \ | ||
144 | spin_lock_irqsave(&ipic_lock, flags); \ | ||
145 | for_each_present_cpu(cpu) { \ | ||
146 | if (!irq_mask_addr[cpu]) \ | ||
147 | break; \ | ||
148 | \ | ||
149 | val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\ | ||
150 | if (enable_irq_for_cpu(cpu, d, m)) \ | ||
151 | val |= (1 << bit); \ | ||
152 | else \ | ||
153 | val &= ~(1 << bit); \ | ||
154 | bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\ | ||
155 | } \ | ||
156 | spin_unlock_irqrestore(&ipic_lock, flags); \ | ||
280 | } | 157 | } |
281 | 158 | ||
282 | static void __dispatch_internal_64(void) | 159 | BUILD_IPIC_INTERNAL(32); |
283 | { | 160 | BUILD_IPIC_INTERNAL(64); |
284 | u64 pending; | ||
285 | static int i; | ||
286 | |||
287 | pending = bcm_readq(irq_stat_addr) & bcm_readq(irq_mask_addr); | ||
288 | |||
289 | if (!pending) | ||
290 | return ; | ||
291 | |||
292 | while (1) { | ||
293 | int to_call = i; | ||
294 | |||
295 | i = (i + 1) & 0x3f; | ||
296 | if (pending & (1ull << to_call)) { | ||
297 | handle_internal(to_call); | ||
298 | break; | ||
299 | } | ||
300 | } | ||
301 | } | ||
302 | 161 | ||
303 | asmlinkage void plat_irq_dispatch(void) | 162 | asmlinkage void plat_irq_dispatch(void) |
304 | { | 163 | { |
@@ -317,8 +176,11 @@ asmlinkage void plat_irq_dispatch(void) | |||
317 | if (cause & CAUSEF_IP1) | 176 | if (cause & CAUSEF_IP1) |
318 | do_IRQ(1); | 177 | do_IRQ(1); |
319 | if (cause & CAUSEF_IP2) | 178 | if (cause & CAUSEF_IP2) |
320 | dispatch_internal(); | 179 | dispatch_internal(0); |
321 | if (!is_ext_irq_cascaded) { | 180 | if (is_ext_irq_cascaded) { |
181 | if (cause & CAUSEF_IP3) | ||
182 | dispatch_internal(1); | ||
183 | } else { | ||
322 | if (cause & CAUSEF_IP3) | 184 | if (cause & CAUSEF_IP3) |
323 | do_IRQ(IRQ_EXT_0); | 185 | do_IRQ(IRQ_EXT_0); |
324 | if (cause & CAUSEF_IP4) | 186 | if (cause & CAUSEF_IP4) |
@@ -335,50 +197,14 @@ asmlinkage void plat_irq_dispatch(void) | |||
335 | * internal IRQs operations: only mask/unmask on PERF irq mask | 197 | * internal IRQs operations: only mask/unmask on PERF irq mask |
336 | * register. | 198 | * register. |
337 | */ | 199 | */ |
338 | static void __internal_irq_mask_32(unsigned int irq) | ||
339 | { | ||
340 | u32 mask; | ||
341 | |||
342 | mask = bcm_readl(irq_mask_addr); | ||
343 | mask &= ~(1 << irq); | ||
344 | bcm_writel(mask, irq_mask_addr); | ||
345 | } | ||
346 | |||
347 | static void __internal_irq_mask_64(unsigned int irq) | ||
348 | { | ||
349 | u64 mask; | ||
350 | |||
351 | mask = bcm_readq(irq_mask_addr); | ||
352 | mask &= ~(1ull << irq); | ||
353 | bcm_writeq(mask, irq_mask_addr); | ||
354 | } | ||
355 | |||
356 | static void __internal_irq_unmask_32(unsigned int irq) | ||
357 | { | ||
358 | u32 mask; | ||
359 | |||
360 | mask = bcm_readl(irq_mask_addr); | ||
361 | mask |= (1 << irq); | ||
362 | bcm_writel(mask, irq_mask_addr); | ||
363 | } | ||
364 | |||
365 | static void __internal_irq_unmask_64(unsigned int irq) | ||
366 | { | ||
367 | u64 mask; | ||
368 | |||
369 | mask = bcm_readq(irq_mask_addr); | ||
370 | mask |= (1ull << irq); | ||
371 | bcm_writeq(mask, irq_mask_addr); | ||
372 | } | ||
373 | |||
374 | static void bcm63xx_internal_irq_mask(struct irq_data *d) | 200 | static void bcm63xx_internal_irq_mask(struct irq_data *d) |
375 | { | 201 | { |
376 | internal_irq_mask(d->irq - IRQ_INTERNAL_BASE); | 202 | internal_irq_mask(d); |
377 | } | 203 | } |
378 | 204 | ||
379 | static void bcm63xx_internal_irq_unmask(struct irq_data *d) | 205 | static void bcm63xx_internal_irq_unmask(struct irq_data *d) |
380 | { | 206 | { |
381 | internal_irq_unmask(d->irq - IRQ_INTERNAL_BASE); | 207 | internal_irq_unmask(d, NULL); |
382 | } | 208 | } |
383 | 209 | ||
384 | /* | 210 | /* |
@@ -389,8 +215,10 @@ static void bcm63xx_external_irq_mask(struct irq_data *d) | |||
389 | { | 215 | { |
390 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; | 216 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; |
391 | u32 reg, regaddr; | 217 | u32 reg, regaddr; |
218 | unsigned long flags; | ||
392 | 219 | ||
393 | regaddr = get_ext_irq_perf_reg(irq); | 220 | regaddr = get_ext_irq_perf_reg(irq); |
221 | spin_lock_irqsave(&epic_lock, flags); | ||
394 | reg = bcm_perf_readl(regaddr); | 222 | reg = bcm_perf_readl(regaddr); |
395 | 223 | ||
396 | if (BCMCPU_IS_6348()) | 224 | if (BCMCPU_IS_6348()) |
@@ -399,16 +227,20 @@ static void bcm63xx_external_irq_mask(struct irq_data *d) | |||
399 | reg &= ~EXTIRQ_CFG_MASK(irq % 4); | 227 | reg &= ~EXTIRQ_CFG_MASK(irq % 4); |
400 | 228 | ||
401 | bcm_perf_writel(reg, regaddr); | 229 | bcm_perf_writel(reg, regaddr); |
230 | spin_unlock_irqrestore(&epic_lock, flags); | ||
231 | |||
402 | if (is_ext_irq_cascaded) | 232 | if (is_ext_irq_cascaded) |
403 | internal_irq_mask(irq + ext_irq_start); | 233 | internal_irq_mask(irq_get_irq_data(irq + ext_irq_start)); |
404 | } | 234 | } |
405 | 235 | ||
406 | static void bcm63xx_external_irq_unmask(struct irq_data *d) | 236 | static void bcm63xx_external_irq_unmask(struct irq_data *d) |
407 | { | 237 | { |
408 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; | 238 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; |
409 | u32 reg, regaddr; | 239 | u32 reg, regaddr; |
240 | unsigned long flags; | ||
410 | 241 | ||
411 | regaddr = get_ext_irq_perf_reg(irq); | 242 | regaddr = get_ext_irq_perf_reg(irq); |
243 | spin_lock_irqsave(&epic_lock, flags); | ||
412 | reg = bcm_perf_readl(regaddr); | 244 | reg = bcm_perf_readl(regaddr); |
413 | 245 | ||
414 | if (BCMCPU_IS_6348()) | 246 | if (BCMCPU_IS_6348()) |
@@ -417,17 +249,21 @@ static void bcm63xx_external_irq_unmask(struct irq_data *d) | |||
417 | reg |= EXTIRQ_CFG_MASK(irq % 4); | 249 | reg |= EXTIRQ_CFG_MASK(irq % 4); |
418 | 250 | ||
419 | bcm_perf_writel(reg, regaddr); | 251 | bcm_perf_writel(reg, regaddr); |
252 | spin_unlock_irqrestore(&epic_lock, flags); | ||
420 | 253 | ||
421 | if (is_ext_irq_cascaded) | 254 | if (is_ext_irq_cascaded) |
422 | internal_irq_unmask(irq + ext_irq_start); | 255 | internal_irq_unmask(irq_get_irq_data(irq + ext_irq_start), |
256 | NULL); | ||
423 | } | 257 | } |
424 | 258 | ||
425 | static void bcm63xx_external_irq_clear(struct irq_data *d) | 259 | static void bcm63xx_external_irq_clear(struct irq_data *d) |
426 | { | 260 | { |
427 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; | 261 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; |
428 | u32 reg, regaddr; | 262 | u32 reg, regaddr; |
263 | unsigned long flags; | ||
429 | 264 | ||
430 | regaddr = get_ext_irq_perf_reg(irq); | 265 | regaddr = get_ext_irq_perf_reg(irq); |
266 | spin_lock_irqsave(&epic_lock, flags); | ||
431 | reg = bcm_perf_readl(regaddr); | 267 | reg = bcm_perf_readl(regaddr); |
432 | 268 | ||
433 | if (BCMCPU_IS_6348()) | 269 | if (BCMCPU_IS_6348()) |
@@ -436,6 +272,7 @@ static void bcm63xx_external_irq_clear(struct irq_data *d) | |||
436 | reg |= EXTIRQ_CFG_CLEAR(irq % 4); | 272 | reg |= EXTIRQ_CFG_CLEAR(irq % 4); |
437 | 273 | ||
438 | bcm_perf_writel(reg, regaddr); | 274 | bcm_perf_writel(reg, regaddr); |
275 | spin_unlock_irqrestore(&epic_lock, flags); | ||
439 | } | 276 | } |
440 | 277 | ||
441 | static int bcm63xx_external_irq_set_type(struct irq_data *d, | 278 | static int bcm63xx_external_irq_set_type(struct irq_data *d, |
@@ -444,6 +281,7 @@ static int bcm63xx_external_irq_set_type(struct irq_data *d, | |||
444 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; | 281 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; |
445 | u32 reg, regaddr; | 282 | u32 reg, regaddr; |
446 | int levelsense, sense, bothedge; | 283 | int levelsense, sense, bothedge; |
284 | unsigned long flags; | ||
447 | 285 | ||
448 | flow_type &= IRQ_TYPE_SENSE_MASK; | 286 | flow_type &= IRQ_TYPE_SENSE_MASK; |
449 | 287 | ||
@@ -478,6 +316,7 @@ static int bcm63xx_external_irq_set_type(struct irq_data *d, | |||
478 | } | 316 | } |
479 | 317 | ||
480 | regaddr = get_ext_irq_perf_reg(irq); | 318 | regaddr = get_ext_irq_perf_reg(irq); |
319 | spin_lock_irqsave(&epic_lock, flags); | ||
481 | reg = bcm_perf_readl(regaddr); | 320 | reg = bcm_perf_readl(regaddr); |
482 | irq %= 4; | 321 | irq %= 4; |
483 | 322 | ||
@@ -522,6 +361,7 @@ static int bcm63xx_external_irq_set_type(struct irq_data *d, | |||
522 | } | 361 | } |
523 | 362 | ||
524 | bcm_perf_writel(reg, regaddr); | 363 | bcm_perf_writel(reg, regaddr); |
364 | spin_unlock_irqrestore(&epic_lock, flags); | ||
525 | 365 | ||
526 | irqd_set_trigger_type(d, flow_type); | 366 | irqd_set_trigger_type(d, flow_type); |
527 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) | 367 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) |
@@ -532,6 +372,18 @@ static int bcm63xx_external_irq_set_type(struct irq_data *d, | |||
532 | return IRQ_SET_MASK_OK_NOCOPY; | 372 | return IRQ_SET_MASK_OK_NOCOPY; |
533 | } | 373 | } |
534 | 374 | ||
375 | #ifdef CONFIG_SMP | ||
376 | static int bcm63xx_internal_set_affinity(struct irq_data *data, | ||
377 | const struct cpumask *dest, | ||
378 | bool force) | ||
379 | { | ||
380 | if (!irqd_irq_disabled(data)) | ||
381 | internal_irq_unmask(data, dest); | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | #endif | ||
386 | |||
535 | static struct irq_chip bcm63xx_internal_irq_chip = { | 387 | static struct irq_chip bcm63xx_internal_irq_chip = { |
536 | .name = "bcm63xx_ipic", | 388 | .name = "bcm63xx_ipic", |
537 | .irq_mask = bcm63xx_internal_irq_mask, | 389 | .irq_mask = bcm63xx_internal_irq_mask, |
@@ -554,12 +406,130 @@ static struct irqaction cpu_ip2_cascade_action = { | |||
554 | .flags = IRQF_NO_THREAD, | 406 | .flags = IRQF_NO_THREAD, |
555 | }; | 407 | }; |
556 | 408 | ||
409 | #ifdef CONFIG_SMP | ||
410 | static struct irqaction cpu_ip3_cascade_action = { | ||
411 | .handler = no_action, | ||
412 | .name = "cascade_ip3", | ||
413 | .flags = IRQF_NO_THREAD, | ||
414 | }; | ||
415 | #endif | ||
416 | |||
557 | static struct irqaction cpu_ext_cascade_action = { | 417 | static struct irqaction cpu_ext_cascade_action = { |
558 | .handler = no_action, | 418 | .handler = no_action, |
559 | .name = "cascade_extirq", | 419 | .name = "cascade_extirq", |
560 | .flags = IRQF_NO_THREAD, | 420 | .flags = IRQF_NO_THREAD, |
561 | }; | 421 | }; |
562 | 422 | ||
423 | static void bcm63xx_init_irq(void) | ||
424 | { | ||
425 | int irq_bits; | ||
426 | |||
427 | irq_stat_addr[0] = bcm63xx_regset_address(RSET_PERF); | ||
428 | irq_mask_addr[0] = bcm63xx_regset_address(RSET_PERF); | ||
429 | irq_stat_addr[1] = bcm63xx_regset_address(RSET_PERF); | ||
430 | irq_mask_addr[1] = bcm63xx_regset_address(RSET_PERF); | ||
431 | |||
432 | switch (bcm63xx_get_cpu_id()) { | ||
433 | case BCM3368_CPU_ID: | ||
434 | irq_stat_addr[0] += PERF_IRQSTAT_3368_REG; | ||
435 | irq_mask_addr[0] += PERF_IRQMASK_3368_REG; | ||
436 | irq_stat_addr[1] = 0; | ||
437 | irq_stat_addr[1] = 0; | ||
438 | irq_bits = 32; | ||
439 | ext_irq_count = 4; | ||
440 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368; | ||
441 | break; | ||
442 | case BCM6328_CPU_ID: | ||
443 | irq_stat_addr[0] += PERF_IRQSTAT_6328_REG(0); | ||
444 | irq_mask_addr[0] += PERF_IRQMASK_6328_REG(0); | ||
445 | irq_stat_addr[1] += PERF_IRQSTAT_6328_REG(1); | ||
446 | irq_stat_addr[1] += PERF_IRQMASK_6328_REG(1); | ||
447 | irq_bits = 64; | ||
448 | ext_irq_count = 4; | ||
449 | is_ext_irq_cascaded = 1; | ||
450 | ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE; | ||
451 | ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE; | ||
452 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328; | ||
453 | break; | ||
454 | case BCM6338_CPU_ID: | ||
455 | irq_stat_addr[0] += PERF_IRQSTAT_6338_REG; | ||
456 | irq_mask_addr[0] += PERF_IRQMASK_6338_REG; | ||
457 | irq_stat_addr[1] = 0; | ||
458 | irq_mask_addr[1] = 0; | ||
459 | irq_bits = 32; | ||
460 | ext_irq_count = 4; | ||
461 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338; | ||
462 | break; | ||
463 | case BCM6345_CPU_ID: | ||
464 | irq_stat_addr[0] += PERF_IRQSTAT_6345_REG; | ||
465 | irq_mask_addr[0] += PERF_IRQMASK_6345_REG; | ||
466 | irq_stat_addr[1] = 0; | ||
467 | irq_mask_addr[1] = 0; | ||
468 | irq_bits = 32; | ||
469 | ext_irq_count = 4; | ||
470 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345; | ||
471 | break; | ||
472 | case BCM6348_CPU_ID: | ||
473 | irq_stat_addr[0] += PERF_IRQSTAT_6348_REG; | ||
474 | irq_mask_addr[0] += PERF_IRQMASK_6348_REG; | ||
475 | irq_stat_addr[1] = 0; | ||
476 | irq_mask_addr[1] = 0; | ||
477 | irq_bits = 32; | ||
478 | ext_irq_count = 4; | ||
479 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348; | ||
480 | break; | ||
481 | case BCM6358_CPU_ID: | ||
482 | irq_stat_addr[0] += PERF_IRQSTAT_6358_REG(0); | ||
483 | irq_mask_addr[0] += PERF_IRQMASK_6358_REG(0); | ||
484 | irq_stat_addr[1] += PERF_IRQSTAT_6358_REG(1); | ||
485 | irq_mask_addr[1] += PERF_IRQMASK_6358_REG(1); | ||
486 | irq_bits = 32; | ||
487 | ext_irq_count = 4; | ||
488 | is_ext_irq_cascaded = 1; | ||
489 | ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE; | ||
490 | ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE; | ||
491 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358; | ||
492 | break; | ||
493 | case BCM6362_CPU_ID: | ||
494 | irq_stat_addr[0] += PERF_IRQSTAT_6362_REG(0); | ||
495 | irq_mask_addr[0] += PERF_IRQMASK_6362_REG(0); | ||
496 | irq_stat_addr[1] += PERF_IRQSTAT_6362_REG(1); | ||
497 | irq_mask_addr[1] += PERF_IRQMASK_6362_REG(1); | ||
498 | irq_bits = 64; | ||
499 | ext_irq_count = 4; | ||
500 | is_ext_irq_cascaded = 1; | ||
501 | ext_irq_start = BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE; | ||
502 | ext_irq_end = BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE; | ||
503 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6362; | ||
504 | break; | ||
505 | case BCM6368_CPU_ID: | ||
506 | irq_stat_addr[0] += PERF_IRQSTAT_6368_REG(0); | ||
507 | irq_mask_addr[0] += PERF_IRQMASK_6368_REG(0); | ||
508 | irq_stat_addr[1] += PERF_IRQSTAT_6368_REG(1); | ||
509 | irq_mask_addr[1] += PERF_IRQMASK_6368_REG(1); | ||
510 | irq_bits = 64; | ||
511 | ext_irq_count = 6; | ||
512 | is_ext_irq_cascaded = 1; | ||
513 | ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE; | ||
514 | ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE; | ||
515 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368; | ||
516 | ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368; | ||
517 | break; | ||
518 | default: | ||
519 | BUG(); | ||
520 | } | ||
521 | |||
522 | if (irq_bits == 32) { | ||
523 | dispatch_internal = __dispatch_internal_32; | ||
524 | internal_irq_mask = __internal_irq_mask_32; | ||
525 | internal_irq_unmask = __internal_irq_unmask_32; | ||
526 | } else { | ||
527 | dispatch_internal = __dispatch_internal_64; | ||
528 | internal_irq_mask = __internal_irq_mask_64; | ||
529 | internal_irq_unmask = __internal_irq_unmask_64; | ||
530 | } | ||
531 | } | ||
532 | |||
563 | void __init arch_init_irq(void) | 533 | void __init arch_init_irq(void) |
564 | { | 534 | { |
565 | int i; | 535 | int i; |
@@ -580,4 +550,14 @@ void __init arch_init_irq(void) | |||
580 | } | 550 | } |
581 | 551 | ||
582 | setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action); | 552 | setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action); |
553 | #ifdef CONFIG_SMP | ||
554 | if (is_ext_irq_cascaded) { | ||
555 | setup_irq(MIPS_CPU_IRQ_BASE + 3, &cpu_ip3_cascade_action); | ||
556 | bcm63xx_internal_irq_chip.irq_set_affinity = | ||
557 | bcm63xx_internal_set_affinity; | ||
558 | |||
559 | cpumask_clear(irq_default_affinity); | ||
560 | cpumask_set_cpu(smp_processor_id(), irq_default_affinity); | ||
561 | } | ||
562 | #endif | ||
583 | } | 563 | } |