cosmetic fix for irq error messages
[openwrt.git] / target / linux / aruba-2.6 / patches / 002-irq.patch
1 diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/aruba/irq.c
2 --- linux-2.6.17/arch/mips/aruba/irq.c  1970-01-01 01:00:00.000000000 +0100
3 +++ linux-2.6.17-openwrt/arch/mips/aruba/irq.c  2006-01-10 00:32:32.000000000 +0100
4 @@ -0,0 +1,433 @@
5 +/**************************************************************************
6 + *
7 + *  BRIEF MODULE DESCRIPTION
8 + *     Interrupt routines for IDT EB434 boards / Atheros boards
9 + *     Modified by Aruba Networks
10 + *
11 + *  Copyright 2004 IDT Inc. (rischelp@idt.com)
12 + *         
13 + *  This program is free software; you can redistribute  it and/or modify it
14 + *  under  the terms of  the GNU General  Public License as published by the
15 + *  Free Software Foundation;  either version 2 of the  License, or (at your
16 + *  option) any later version.
17 + *
18 + *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
19 + *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
20 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
21 + *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
22 + *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 + *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
24 + *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 + *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
26 + *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 + *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 + *
29 + *  You should have received a copy of the  GNU General Public License along
30 + *  with this program; if not, write  to the Free Software Foundation, Inc.,
31 + *  675 Mass Ave, Cambridge, MA 02139, USA.
32 + *
33 + *
34 + **************************************************************************
35 + * May 2004 rkt, neb
36 + *
37 + * Initial Release
38 + *
39 + * 
40 + *
41 + **************************************************************************
42 + */
43 +
44 +#include <linux/errno.h>
45 +#include <linux/init.h>
46 +#include <linux/kernel_stat.h>
47 +#include <linux/module.h>
48 +#include <linux/signal.h>
49 +#include <linux/sched.h>
50 +#include <linux/types.h>
51 +#include <linux/interrupt.h>
52 +#include <linux/ioport.h>
53 +#include <linux/timex.h>
54 +#include <linux/slab.h>
55 +#include <linux/random.h>
56 +#include <linux/delay.h>
57 +
58 +#include <asm/bitops.h>
59 +#include <asm/bootinfo.h>
60 +#include <asm/io.h>
61 +#include <asm/mipsregs.h>
62 +#include <asm/system.h>
63 +#include <asm/idt-boards/rc32434/rc32434.h>
64 +#include <asm/idt-boards/rc32434/rc32434_gpio.h>
65 +
66 +#include <asm/irq.h>
67 +
68 +#undef DEBUG_IRQ
69 +#ifdef DEBUG_IRQ
70 +/* note: prints function name for you */
71 +#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
72 +#else
73 +#define DPRINTK(fmt, args...)
74 +#endif
75 +
76 +extern void aruba_timer_interrupt(struct pt_regs *regs);
77 +static unsigned int startup_irq(unsigned int irq);
78 +static void end_irq(unsigned int irq_nr);
79 +static void mask_and_ack_irq(unsigned int irq_nr);
80 +static void aruba_enable_irq(unsigned int irq_nr);
81 +static void aruba_disable_irq(unsigned int irq_nr);
82 +
83 +extern void __init init_generic_irq(void);
84 +
85 +typedef struct {
86 +       u32 mask;
87 +       volatile u32 *base_addr;
88 +} intr_group_t;
89 +
90 +static const intr_group_t intr_group_merlot[NUM_INTR_GROUPS] = {
91 +       {0xffffffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0)},
92 +};
93 +
94 +#define READ_PEND_MERLOT(base) (*((volatile unsigned long *)(0xbc003010)))
95 +#define READ_MASK_MERLOT(base) (*((volatile unsigned long *)(0xbc003014)))
96 +#define WRITE_MASK_MERLOT(base, val) ((*((volatile unsigned long *)(0xbc003014))) = (val), READ_MASK_MERLOT())
97 +
98 +static const intr_group_t intr_group_muscat[NUM_INTR_GROUPS] = {
99 +       {0x0000efff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)},
100 +       {0x00001fff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET)},
101 +       {0x00000007, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET)},
102 +       {0x0003ffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET)},
103 +       {0xffffffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 4 * IC_GROUP_OFFSET)}
104 +};
105 +
106 +#define READ_PEND_MUSCAT(base) (*(base))
107 +#define READ_MASK_MUSCAT(base) (*(base + 2))
108 +#define WRITE_MASK_MUSCAT(base, val) (*(base + 2) = (val))
109 +
110 +static inline int irq_to_group(unsigned int irq_nr)
111 +{
112 +       switch (mips_machtype) {
113 +               case MACH_ARUBA_AP70:
114 +                       return ((irq_nr - GROUP0_IRQ_BASE) >> 5);
115 +               case MACH_ARUBA_AP65:
116 +               case MACH_ARUBA_AP60:
117 +               default:
118 +                       return 0;
119 +       }
120 +}
121 +
122 +static inline int group_to_ip(unsigned int group)
123 +{
124 +       switch (mips_machtype) {
125 +               case MACH_ARUBA_AP70:
126 +                       return group + 2;
127 +               case MACH_ARUBA_AP65:
128 +               case MACH_ARUBA_AP60:
129 +               default:
130 +                       return 6;
131 +       }
132 +}
133 +
134 +static inline void enable_local_irq(unsigned int ip)
135 +{
136 +       set_c0_status(0x100 << ip);
137 +       irq_enable_hazard();
138 +}
139 +
140 +static inline void disable_local_irq(unsigned int ip)
141 +{
142 +       clear_c0_status(0x100 << ip);
143 +       irq_disable_hazard();
144 +}
145 +
146 +static void aruba_enable_irq(unsigned int irq_nr)
147 +{
148 +       unsigned long flags;
149 +       int ip = irq_nr - GROUP0_IRQ_BASE;
150 +       unsigned int group, intr_bit;
151 +       volatile unsigned int *addr;
152 +
153 +
154 +       local_irq_save(flags);
155 +       
156 +       if (ip < 0) {
157 +               enable_local_irq(irq_nr);
158 +       } else {
159 +               // calculate group
160 +               switch (mips_machtype) {
161 +                       case MACH_ARUBA_AP70:
162 +                               group = ip >> 5;
163 +                               break;
164 +                       case MACH_ARUBA_AP65:
165 +                       case MACH_ARUBA_AP60:
166 +                       default:
167 +                               group = 0;
168 +                               break;
169 +               }
170 +
171 +               // calc interrupt bit within group
172 +               ip -= (group << 5);
173 +               intr_bit = 1 << ip;
174 +
175 +               switch (mips_machtype) {
176 +                       case MACH_ARUBA_AP70:
177 +                               addr = intr_group_muscat[group].base_addr;
178 +                               WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit);
179 +                               break;
180 +                       case MACH_ARUBA_AP65:
181 +                       case MACH_ARUBA_AP60:
182 +                       default:
183 +                               addr = intr_group_merlot[group].base_addr;
184 +                               WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit);
185 +                               break;
186 +               }
187 +               enable_local_irq(group_to_ip(group));
188 +       }
189 +
190 +       back_to_back_c0_hazard();
191 +       local_irq_restore(flags);
192 +
193 +}
194 +
195 +static void aruba_disable_irq(unsigned int irq_nr)
196 +{
197 +       unsigned long flags;
198 +       int ip = irq_nr - GROUP0_IRQ_BASE;
199 +       unsigned int group, intr_bit, mask;
200 +       volatile unsigned int *addr;
201 +
202 +       local_irq_save(flags);
203 +
204 +       if (ip < 0) {
205 +               disable_local_irq(irq_nr);
206 +       } else {
207 +               // calculate group
208 +               switch (mips_machtype) {
209 +                       case MACH_ARUBA_AP70:
210 +                               group = ip >> 5;
211 +                               break;
212 +                       case MACH_ARUBA_AP65:
213 +                       case MACH_ARUBA_AP60:
214 +                       default:
215 +                               group = 0;
216 +                               break;
217 +               }
218 +
219 +               // calc interrupt bit within group
220 +               ip -= group << 5;
221 +               intr_bit = 1 << ip;
222 +
223 +               switch (mips_machtype) {
224 +                       case MACH_ARUBA_AP70:
225 +                               addr = intr_group_muscat[group].base_addr;
226 +                               // mask intr within group
227 +                               mask = READ_MASK_MUSCAT(addr);
228 +                               mask |= intr_bit;
229 +                               WRITE_MASK_MUSCAT(addr, mask);
230 +       
231 +                               /*
232 +                                  if there are no more interrupts enabled in this
233 +                                  group, disable corresponding IP
234 +                                */
235 +                               if (mask == intr_group_muscat[group].mask)
236 +                                       disable_local_irq(group_to_ip(group));
237 +                               break;
238 +                       case MACH_ARUBA_AP65:
239 +                       case MACH_ARUBA_AP60:
240 +                       default:
241 +                               addr = intr_group_merlot[group].base_addr;
242 +                               // mask intr within group
243 +                               mask = READ_MASK_MERLOT(addr);
244 +                               mask &= ~intr_bit;
245 +                               if (!mask)
246 +                                       disable_local_irq(group_to_ip(group));
247 +                               WRITE_MASK_MERLOT(addr, mask);
248 +                               break;
249 +               }
250 +       }
251 +
252 +       back_to_back_c0_hazard();
253 +       local_irq_restore(flags);
254 +}
255 +
256 +static unsigned int startup_irq(unsigned int irq_nr)
257 +{
258 +       aruba_enable_irq(irq_nr);
259 +       return 0;
260 +}
261 +
262 +static void shutdown_irq(unsigned int irq_nr)
263 +{
264 +       aruba_disable_irq(irq_nr);
265 +}
266 +
267 +static void mask_and_ack_irq(unsigned int irq_nr)
268 +{
269 +       aruba_disable_irq(irq_nr);
270 +}
271 +
272 +static void end_irq(unsigned int irq_nr)
273 +{
274 +
275 +       int ip = irq_nr - GROUP0_IRQ_BASE;
276 +       unsigned int intr_bit, group;
277 +       volatile unsigned int *addr;
278 +
279 +
280 +       if (irq_desc[irq_nr].status & (IRQ_DISABLED | IRQ_INPROGRESS)) {
281 +               printk("warning: end_irq %d did not enable (%x)\n",
282 +                      irq_nr, irq_desc[irq_nr].status);
283 +               /* fall through; enable the interrupt
284 +                * -- It'll get stuck otherwise
285 +                */
286 +
287 +       } 
288 +
289 +       if (ip<0) {
290 +               enable_local_irq(irq_nr);
291 +       } else {
292 +
293 +               switch (mips_machtype) {
294 +                       case MACH_ARUBA_AP70:
295 +                               if (irq_nr == GROUP4_IRQ_BASE + 9)       idt_gpio->gpioistat &= 0xfffffdff;
296 +                               else if (irq_nr == GROUP4_IRQ_BASE + 10) idt_gpio->gpioistat &= 0xfffffbff;
297 +                               else if (irq_nr == GROUP4_IRQ_BASE + 11) idt_gpio->gpioistat &= 0xfffff7ff;
298 +                               else if (irq_nr == GROUP4_IRQ_BASE + 12) idt_gpio->gpioistat &= 0xffffefff;
299 +               
300 +                               group = ip >> 5;
301 +                       
302 +                               // calc interrupt bit within group
303 +                               ip -= (group << 5);
304 +                               intr_bit = 1 << ip;
305 +               
306 +                               // first enable the IP mapped to this IRQ
307 +                               enable_local_irq(group_to_ip(group));
308 +               
309 +                               addr = intr_group_muscat[group].base_addr;
310 +                               // unmask intr within group
311 +                               WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit);
312 +                               break;
313 +
314 +                       case MACH_ARUBA_AP65:
315 +                       case MACH_ARUBA_AP60:
316 +                       default:
317 +                               group = 0;
318 +       
319 +                               // calc interrupt bit within group
320 +                               intr_bit = 1 << ip;
321 +       
322 +                               // first enable the IP mapped to this IRQ
323 +                               enable_local_irq(group_to_ip(group));
324 +       
325 +                               addr = intr_group_merlot[group].base_addr;
326 +                               // unmask intr within group
327 +                               WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit);
328 +                               break;
329 +               }
330 +       }
331 +}
332 +
333 +static struct hw_interrupt_type aruba_irq_type = {
334 +       .typename = "ARUBA",
335 +       .startup = startup_irq,
336 +       .shutdown = shutdown_irq,
337 +       .enable = aruba_enable_irq,
338 +       .disable = aruba_disable_irq,
339 +       .ack = mask_and_ack_irq,
340 +       .end = end_irq,
341 +};
342 +
343 +void __init arch_init_irq(void)
344 +{
345 +       int i;
346 +       printk("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS);
347 +       memset(irq_desc, 0, sizeof(irq_desc));
348 +
349 +       set_c0_status(0xFF00);
350 +
351 +       for (i = 0; i < RC32434_NR_IRQS; i++) {
352 +               irq_desc[i].status = IRQ_DISABLED;
353 +               irq_desc[i].action = NULL;
354 +               irq_desc[i].depth = 1;
355 +               irq_desc[i].handler = &aruba_irq_type;
356 +               spin_lock_init(&irq_desc[i].lock);
357 +       }
358 +}
359 +
360 +/* Main Interrupt dispatcher */
361 +
362 +void plat_irq_dispatch(struct pt_regs *regs)
363 +{
364 +       unsigned int pend, group, ip;
365 +       volatile unsigned int *addr;
366 +       unsigned long cp0_cause = read_c0_cause() & read_c0_status() & CAUSEF_IP;
367 +
368 +       if (cp0_cause & CAUSEF_IP7)
369 +               return aruba_timer_interrupt(regs);
370 +
371 +       if(cp0_cause == 0) {
372 +               printk("INTERRUPT(S) FIRED WHILE MASKED\n");
373 +#ifdef ARUBA_DEBUG
374 +               // debuging use -- figure out which interrupt(s) fired
375 +               cp0_cause = read_c0_cause() & CAUSEF_IP;
376 +               while (cp0_cause) {
377 +                       unsigned long intr_bit;
378 +                       unsigned int irq_nr;
379 +                       intr_bit = (31 - rc32434_clz(cp0_cause));
380 +                       irq_nr = intr_bit - GROUP0_IRQ_BASE;
381 +                       printk(" ---> MASKED IRQ %d\n",irq_nr);
382 +                       cp0_cause &= ~(1 << intr_bit);
383 +               }
384 +#endif
385 +               return;
386 +       }
387 +
388 +       switch (mips_machtype) {
389 +               case MACH_ARUBA_AP70:
390 +                       if ((ip = (cp0_cause & 0x7c00))) {
391 +                               group = 21 - rc32434_clz(ip);
392 +               
393 +                               addr = intr_group_muscat[group].base_addr;
394 +               
395 +                               pend = READ_PEND_MUSCAT(addr);
396 +                               pend &= ~READ_MASK_MUSCAT(addr);        // only unmasked interrupts
397 +                               pend = 39 - rc32434_clz(pend);
398 +                               do_IRQ((group << 5) + pend, regs);
399 +                       }
400 +                       break;
401 +               case MACH_ARUBA_AP65:
402 +               case MACH_ARUBA_AP60:
403 +               default:
404 +                       if (cp0_cause & 0x4000) { // 1 << (8 +6) == irq 6
405 +                               // Misc Interrupt
406 +                               group = 0;
407 +                               addr = intr_group_merlot[group].base_addr;
408 +                               pend = READ_PEND_MERLOT(addr);
409 +                               pend &= READ_MASK_MERLOT(addr); // only unmasked interrupts
410 +                               /* handle one misc interrupt at a time */
411 +                               while (pend)
412 +                               {
413 +                                       unsigned long intr_bit;
414 +                                       unsigned int irq_nr;
415 +
416 +                                       intr_bit = (31 - rc32434_clz(pend));
417 +                                       irq_nr = intr_bit + GROUP0_IRQ_BASE;
418 +
419 +                                       do_IRQ(irq_nr, regs);
420 +                                       pend &= ~(1 << intr_bit);
421 +                               }
422 +                       } else if (cp0_cause & 0x3c00) { // irq 2-5
423 +                               while (cp0_cause)
424 +                               {
425 +                                       unsigned long intr_bit;
426 +                                       unsigned int irq_nr;
427 +
428 +                                       intr_bit = (31 - rc32434_clz(cp0_cause));
429 +                                       irq_nr = intr_bit - GROUP0_IRQ_BASE;
430 +
431 +                                       do_IRQ(irq_nr, regs);
432 +                                       cp0_cause &= ~(1 << intr_bit);
433 +                               }
434 +                       }
435 +                       break;
436 +       }
437 +}