Fix typo in wpa_supplicant (#4208)
[librecmc/librecmc.git] / target / linux / brcm63xx / patches-2.6.25 / 060-bcm963xx_rewrite_irq_handling_code.patch
1 From 9a70f2dcb24a5aab29386373c86ba035acba4891 Mon Sep 17 00:00:00 2001
2 From: Axel Gembe <ago@bastart.eu.org>
3 Date: Sun, 18 May 2008 12:07:21 +0200
4 Subject: [PATCH] bcm963xx: rewrite irq handling code
5
6 This patch adds interrupt handling as on AR7. The old code was very messy and
7 didn't work too well.
8
9 Signed-off-by: Axel Gembe <ago@bastart.eu.org>
10 ---
11  arch/mips/bcm963xx/irq.c                  |  308 ++++++++++-------------------
12  drivers/serial/bcm63xx_cons.c             |   13 +-
13  include/asm-mips/mach-bcm963xx/bcm_intr.h |   18 +--
14  3 files changed, 119 insertions(+), 220 deletions(-)
15
16 --- a/arch/mips/bcm963xx/irq.c
17 +++ b/arch/mips/bcm963xx/irq.c
18 @@ -1,259 +1,159 @@
19  /*
20 -<:copyright-gpl 
21 - Copyright 2002 Broadcom Corp. All Rights Reserved. 
22
23 - This program is free software; you can distribute it and/or modify it 
24 - under the terms of the GNU General Public License (Version 2) as 
25 - published by the Free Software Foundation. 
26
27 - This program is distributed in the hope it will be useful, but WITHOUT 
28 - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
29 - FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
30 - for more details. 
31
32 - You should have received a copy of the GNU General Public License along 
33 - with this program; if not, write to the Free Software Foundation, Inc., 
34 - 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 
35 -:>
36 -*/
37 -/*
38 - * Interrupt control functions for Broadcom 963xx MIPS boards
39 + * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
40 + * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org>
41 + * Copyright (C) 2008 Axel Gembe <ago@bastart.eu.org>
42 + *
43 + * This program is free software; you can redistribute it and/or modify
44 + * it under the terms of the GNU General Public License as published by
45 + * the Free Software Foundation; either version 2 of the License, or
46 + * (at your option) any later version.
47 + *
48 + * This program is distributed in the hope that it will be useful,
49 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
50 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
51 + * GNU General Public License for more details.
52 + *
53 + * You should have received a copy of the GNU General Public License
54 + * along with this program; if not, write to the Free Software
55 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
56   */
57  
58 -#include <asm/atomic.h>
59 -
60 -#include <linux/delay.h>
61 -#include <linux/init.h>
62 -#include <linux/ioport.h>
63 -#include <linux/irq.h>
64  #include <linux/interrupt.h>
65 -#include <linux/kernel.h>
66 -#include <linux/slab.h>
67 -#include <linux/module.h>
68 +#include <linux/io.h>
69  
70 -#include <asm/irq.h>
71 +#include <asm/irq_cpu.h>
72  #include <asm/mipsregs.h>
73 -#include <asm/addrspace.h>
74 -#include <asm/signal.h>
75 +
76  #include <6348_map_part.h>
77  #include <6348_intr.h>
78  #include <bcm_map_part.h>
79  #include <bcm_intr.h>
80  
81 -static void irq_dispatch_int(void)
82 -{
83 -       unsigned int pendingIrqs;
84 -       static unsigned int irqBit;
85 -       static unsigned int isrNumber = 31;
86 -
87 -       pendingIrqs = PERF->IrqStatus & PERF->IrqMask;
88 -       if (!pendingIrqs) {
89 -               return;
90 -       }
91 +static int bcm963xx_irq_base;
92  
93 -       while (1) {
94 -       irqBit <<= 1;
95 -       isrNumber++;
96 -       if (isrNumber == 32) {
97 -               isrNumber = 0;
98 -               irqBit = 0x1;
99 -       }
100 -       if (pendingIrqs & irqBit) {
101 -                       PERF->IrqMask &= ~irqBit; // mask
102 -                       do_IRQ(isrNumber + INTERNAL_ISR_TABLE_OFFSET);
103 -               break;
104 -       }
105 -       }
106 +void bcm963xx_unmask_irq(unsigned int irq)
107 +{
108 +       PERF->IrqMask |= (1 << (irq - bcm963xx_irq_base));
109  }
110  
111 -static void irq_dispatch_ext(uint32 irq)
112 +void bcm963xx_mask_irq(unsigned int irq)
113  {
114 -       if (!(PERF->ExtIrqCfg & (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)))) {
115 -       printk("**** Ext IRQ mask. Should not dispatch ****\n");
116 -       }
117 -       /* disable and clear interrupt in the controller */
118 -       PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));
119 -       PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
120 -       do_IRQ(irq);
121 +       PERF->IrqMask &= ~(1 << (irq - bcm963xx_irq_base));
122  }
123  
124 -
125 -//extern void brcm_timer_interrupt(struct pt_regs *regs);
126 -
127 -asmlinkage void plat_irq_dispatch(void)
128 +void bcm963xx_ack_irq(unsigned int irq)
129  {
130 -       unsigned long cause;
131 -
132 -       cause = read_c0_status() & read_c0_cause() & ST0_IM;
133 -       if (cause & CAUSEF_IP7)
134 -               do_IRQ(7);
135 -       else if (cause & CAUSEF_IP2)
136 -               irq_dispatch_int();
137 -       else if (cause & CAUSEF_IP3)
138 -               irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_0);
139 -       else if (cause & CAUSEF_IP4)
140 -               irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_1);
141 -       else if (cause & CAUSEF_IP5)
142 -               irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_2);
143 -       else if (cause & CAUSEF_IP6) {
144 -               irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_3);
145 -               local_irq_disable();
146 -       }
147 +       PERF->IrqStatus &= ~(1 << (irq - bcm963xx_irq_base));
148  }
149  
150 -
151 -void enable_brcm_irq(unsigned int irq)
152 +void bcm963xx_unmask_ext_irq(unsigned int irq)
153  {
154 -       unsigned long flags;
155 -
156 -       local_irq_save(flags);
157 -       if( irq >= INTERNAL_ISR_TABLE_OFFSET ) {
158 -       PERF->IrqMask |= (1 << (irq - INTERNAL_ISR_TABLE_OFFSET));
159 -       }
160 -       else if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) {
161 -       /* enable and clear interrupt in the controller */
162 -       PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));
163         PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
164 -       }
165 -       local_irq_restore(flags);
166  }
167  
168 -void disable_brcm_irq(unsigned int irq)
169 +void bcm963xx_mask_ext_irq(unsigned int irq)
170  {
171 -       unsigned long flags;
172 -
173 -       local_irq_save(flags);
174 -       if( irq >= INTERNAL_ISR_TABLE_OFFSET ) {
175 -       PERF->IrqMask &= ~(1 << (irq - INTERNAL_ISR_TABLE_OFFSET));
176 -       }
177 -       else if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) {
178 -       /* disable interrupt in the controller */
179         PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
180 -       }
181 -       local_irq_restore(flags);
182  }
183  
184 -void ack_brcm_irq(unsigned int irq)
185 +void bcm963xx_ack_ext_irq(unsigned int irq)
186  {
187 -       /* Already done in brcm_irq_dispatch */
188 +       PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));
189  }
190  
191 -unsigned int startup_brcm_irq(unsigned int irq)
192 +static void bcm963xx_dispatch_ext_irq(unsigned int irq)
193  {
194 -       enable_brcm_irq(irq);
195 -
196 -       return 0; /* never anything pending */
197 +       bcm963xx_ack_ext_irq(irq);
198 +       bcm963xx_mask_ext_irq(irq);
199 +       do_IRQ(irq);
200  }
201  
202 -unsigned int startup_brcm_none(unsigned int irq)
203 +static void bcm963xx_cascade(void)
204  {
205 -       return 0;
206 -}
207 +       uint32_t pending, bit, irq;
208  
209 -void end_brcm_irq(unsigned int irq)
210 -{
211 -       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
212 -               enable_brcm_irq(irq);
213 -}
214 +       if (!(pending = PERF->IrqStatus & PERF->IrqMask))
215 +               return;
216  
217 -void end_brcm_none(unsigned int irq)
218 -{
219 -}
220 +       for (irq = 0, bit = 1; irq < 32; irq++, bit <<= 1) {
221 +               if (pending & bit) {
222 +                       bcm963xx_ack_irq(irq + bcm963xx_irq_base);
223 +                       bcm963xx_mask_irq(irq + bcm963xx_irq_base);
224 +                       do_IRQ(irq + bcm963xx_irq_base);
225 +                       return;
226 +               }
227 +       }
228 +
229 +       spurious_interrupt();
230 +}
231 +
232 +static struct irq_chip bcm963xx_irq_type = {
233 +       .name = "bcm963xx",
234 +       .unmask = bcm963xx_unmask_irq,
235 +       .mask = bcm963xx_mask_irq,
236 +       .ack = bcm963xx_ack_irq
237 +};
238  
239 -static struct hw_interrupt_type brcm_irq_type = {
240 -       .typename       = "MIPS",
241 -       .startup        = startup_brcm_irq,
242 -       .shutdown       = disable_brcm_irq,
243 -       .enable = enable_brcm_irq,
244 -       .disable        = disable_brcm_irq,
245 -       .ack    = ack_brcm_irq,
246 -       .end    = end_brcm_irq,
247 -       .set_affinity = NULL
248 +static struct irq_chip bcm963xx_ext_irq_type = {
249 +       .name = "bcm963xx_ext",
250 +       .unmask = bcm963xx_unmask_ext_irq,
251 +       .mask = bcm963xx_mask_ext_irq,
252 +       .ack = bcm963xx_ack_ext_irq,
253  };
254  
255 -static struct hw_interrupt_type brcm_irq_no_end_type = {
256 -       .typename       = "MIPS",
257 -       .startup        = startup_brcm_none,
258 -       .shutdown       = disable_brcm_irq,
259 -       .enable = enable_brcm_irq,
260 -       .disable        = disable_brcm_irq,
261 -       .ack    = ack_brcm_irq,
262 -       .end    = end_brcm_none,
263 -       .set_affinity = NULL
264 +static struct irqaction bcm963xx_cascade_action = {
265 +       .handler = no_action,
266 +       .name = "BCM963xx cascade interrupt"
267  };
268  
269 -void __init arch_init_irq(void)
270 +static void __init bcm963xx_irq_init(int base)
271  {
272         int i;
273  
274 -       clear_c0_status(ST0_BEV);
275 -       change_c0_status(ST0_IM, (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4));
276 +       bcm963xx_irq_base = base;
277  
278 -       for (i = 0; i < NR_IRQS; i++) {
279 -               irq_desc[i].status = IRQ_DISABLED;
280 -               irq_desc[i].action = 0;
281 -               irq_desc[i].depth = 1;
282 -               irq_desc[i].chip = &brcm_irq_type;
283 -       }
284 +       /* External IRQs */
285 +       set_irq_chip_and_handler(INTERRUPT_ID_EXTERNAL_0, &bcm963xx_ext_irq_type,
286 +                                handle_level_irq);
287 +       set_irq_chip_and_handler(INTERRUPT_ID_EXTERNAL_1, &bcm963xx_ext_irq_type,
288 +                                handle_level_irq);
289 +       set_irq_chip_and_handler(INTERRUPT_ID_EXTERNAL_2, &bcm963xx_ext_irq_type,
290 +                                handle_level_irq);
291 +       set_irq_chip_and_handler(INTERRUPT_ID_EXTERNAL_3, &bcm963xx_ext_irq_type,
292 +                                handle_level_irq);
293 +
294 +       for (i = 0; i < 32; i++) {
295 +               set_irq_chip_and_handler(base + i, &bcm963xx_irq_type,
296 +                                        handle_level_irq);
297 +       }
298 +
299 +       setup_irq(2, &bcm963xx_cascade_action);
300 +       setup_irq(bcm963xx_irq_base, &bcm963xx_cascade_action);
301 +       set_c0_status(IE_IRQ0);
302  }
303  
304 -int request_external_irq(unsigned int irq, 
305 -       FN_HANDLER handler,
306 -               unsigned long irqflags, 
307 -               const char * devname,
308 -               void *dev_id)
309 +asmlinkage void plat_irq_dispatch(void)
310  {
311 -       unsigned long flags;
312 -
313 -       local_irq_save(flags);
314 +       unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
315  
316 -       PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));      // Clear
317 -       PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));      // Mask
318 -       PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_INSENS_SHFT));    // Edge insesnsitive
319 -       PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_LEVEL_SHFT));      // Level triggered
320 -       PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_SENSE_SHFT));     // Low level
321 -
322 -       local_irq_restore(flags);
323 -
324 -       return( request_irq(irq, handler, irqflags, devname, dev_id) );
325 +       if (pending & STATUSF_IP7)              /* cpu timer */
326 +               do_IRQ(7);
327 +       else if (pending & STATUSF_IP2)         /* internal interrupt cascade */
328 +               bcm963xx_cascade();
329 +       else if (pending & STATUSF_IP3)
330 +               bcm963xx_dispatch_ext_irq(INTERRUPT_ID_EXTERNAL_0);
331 +       else if (pending & STATUSF_IP4)
332 +               bcm963xx_dispatch_ext_irq(INTERRUPT_ID_EXTERNAL_1);
333 +       else if (pending & STATUSF_IP5)
334 +               bcm963xx_dispatch_ext_irq(INTERRUPT_ID_EXTERNAL_2);
335 +       else if (pending & STATUSF_IP6)
336 +               bcm963xx_dispatch_ext_irq(INTERRUPT_ID_EXTERNAL_3);
337 +       else
338 +               spurious_interrupt();
339  }
340  
341 -/* VxWorks compatibility function(s). */
342 -
343 -unsigned int BcmHalMapInterrupt(FN_HANDLER pfunc, unsigned int param,
344 -       unsigned int interruptId)
345 +void __init arch_init_irq(void)
346  {
347 -       int nRet = -1;
348 -       char *devname;
349 -
350 -       devname = kmalloc(16, GFP_KERNEL);
351 -       if (devname)
352 -               sprintf( devname, "brcm_%d", interruptId );
353 -
354 -       /* Set the IRQ description to not automatically enable the interrupt at
355 -        * the end of an ISR.  The driver that handles the interrupt must
356 -        * explicitly call BcmHalInterruptEnable or enable_brcm_irq.  This behavior
357 -        * is consistent with interrupt handling on VxWorks.
358 -        */
359 -       irq_desc[interruptId].chip = &brcm_irq_no_end_type;
360 -
361 -       if( interruptId >= INTERNAL_ISR_TABLE_OFFSET )
362 -       {       
363 -               printk("BcmHalMapInterrupt : internal IRQ\n");
364 -               nRet = request_irq( interruptId, pfunc, IRQF_DISABLED, devname, (void *) param );
365 -       }
366 -       else if (interruptId >= INTERRUPT_ID_EXTERNAL_0 && interruptId <= INTERRUPT_ID_EXTERNAL_3)
367 -       {
368 -               printk("BcmHalMapInterrupt : external IRQ\n");
369 -               nRet = request_external_irq( interruptId, pfunc, IRQF_DISABLED, devname, (void *) param );
370 -       }
371 -
372 -       return( nRet );
373 +       mips_cpu_irq_init();
374 +       bcm963xx_irq_init(INTERNAL_ISR_TABLE_OFFSET);
375  }
376 -
377 -
378 -EXPORT_SYMBOL(enable_brcm_irq);
379 -EXPORT_SYMBOL(disable_brcm_irq);
380 -EXPORT_SYMBOL(request_external_irq);
381 -EXPORT_SYMBOL(BcmHalMapInterrupt);
382 -
383 --- a/drivers/serial/bcm63xx_cons.c
384 +++ b/drivers/serial/bcm63xx_cons.c
385 @@ -267,7 +267,7 @@
386         }
387  
388         // Clear the interrupt
389 -       enable_brcm_irq(INTERRUPT_ID_UART);
390 +//     bcm963xx_unmask_irq(INTERRUPT_ID_UART);
391  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
392         return IRQ_HANDLED;
393  #endif
394 @@ -880,7 +880,7 @@
395         info->count++;
396         tty->driver_data = info;
397         info->tty = tty;
398 -       enable_brcm_irq(INTERRUPT_ID_UART);
399 +       bcm963xx_unmask_irq(INTERRUPT_ID_UART);
400  
401         // Start up serial port
402         retval = startup(info);
403 @@ -927,7 +927,7 @@
404  -------------------------------------------------------------------------- */
405  static int __init bcm63xx_serialinit(void)
406  {
407 -       int i, flags;
408 +       int i, flags, res;
409         struct bcm_serial *info;
410  
411         // Print the driver version information
412 @@ -981,7 +981,12 @@
413                  */
414                 if (!info->port)
415                         return 0;
416 -               BcmHalMapInterrupt(bcm_interrupt, 0, INTERRUPT_ID_UART);
417 +
418 +               res = request_irq(INTERRUPT_ID_UART, bcm_interrupt, 0, "bcm-uart", NULL);
419 +               if (res) {
420 +                       spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
421 +                       return res;
422 +               }
423         }
424  
425         /* order matters here... the trick is that flags
426 --- a/include/asm-mips/mach-bcm963xx/bcm_intr.h
427 +++ b/include/asm-mips/mach-bcm963xx/bcm_intr.h
428 @@ -39,18 +39,12 @@
429  typedef int (*FN_HANDLER) (int, void *);
430  
431  /* prototypes */
432 -extern void enable_brcm_irq(unsigned int irq);
433 -extern void disable_brcm_irq(unsigned int irq);
434 -extern int request_external_irq(unsigned int irq,
435 -    FN_HANDLER handler, unsigned long irqflags, 
436 -    const char * devname, void *dev_id);
437 -extern unsigned int BcmHalMapInterrupt(FN_HANDLER isr, unsigned int param,
438 -    unsigned int interruptId);
439 -extern void dump_intr_regs(void);
440 -
441 -/* compatibility definitions */
442 -#define BcmHalInterruptEnable(irq)      enable_brcm_irq( irq )
443 -#define BcmHalInterruptDisable(irq)     disable_brcm_irq( irq )
444 +extern void bcm963xx_unmask_irq(unsigned int irq);
445 +extern void bcm963xx_mask_irq(unsigned int irq);
446 +extern void bcm963xx_ack_irq(unsigned int irq);
447 +extern void bcm963xx_unmask_ext_irq(unsigned int irq);
448 +extern void bcm963xx_mask_ext_irq(unsigned int irq);
449 +extern void bcm963xx_ack_ext_irq(unsigned int irq);
450  
451  #ifdef __cplusplus
452      }