[PATCH] CRIS update: IRQ
authorMikael Starvik <mikael.starvik@axis.com>
Wed, 27 Jul 2005 18:44:36 +0000 (11:44 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 27 Jul 2005 23:26:00 +0000 (16:26 -0700)
Use the generic IRQ framework

Signed-off-by: Mikael Starvik <starvik@axis.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

arch/cris/arch-v10/kernel/irq.c
arch/cris/kernel/irq.c
include/asm-cris/arch-v10/irq.h
include/asm-cris/hardirq.h
include/asm-cris/hw_irq.h [new file with mode: 0644]
include/asm-cris/irq.h

index b2f16d6..4b368a1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.2 2004/06/09 05:30:27 starvik Exp $
+/* $Id: irq.c,v 1.4 2005/01/04 12:22:28 starvik Exp $
  *
  *     linux/arch/cris/kernel/irq.c
  *
  */
 
 #include <asm/irq.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/config.h>
 
-irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq prologue */
+#define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
+#define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
 
 /* don't use set_int_vector, it bypasses the linux interrupt handlers. it is
  * global just so that the kernel gdb can use it.
@@ -102,41 +104,52 @@ static void (*interrupt[NR_IRQS])(void) = {
        IRQ31_interrupt
 };
 
-static void (*bad_interrupt[NR_IRQS])(void) = {
-        NULL, NULL,
-       NULL, bad_IRQ3_interrupt,
-       bad_IRQ4_interrupt, bad_IRQ5_interrupt,
-       bad_IRQ6_interrupt, bad_IRQ7_interrupt,
-       bad_IRQ8_interrupt, bad_IRQ9_interrupt,
-       bad_IRQ10_interrupt, bad_IRQ11_interrupt,
-       bad_IRQ12_interrupt, bad_IRQ13_interrupt,
-       NULL, NULL,
-       bad_IRQ16_interrupt, bad_IRQ17_interrupt,
-       bad_IRQ18_interrupt, bad_IRQ19_interrupt,
-       bad_IRQ20_interrupt, bad_IRQ21_interrupt,
-       bad_IRQ22_interrupt, bad_IRQ23_interrupt,
-       bad_IRQ24_interrupt, bad_IRQ25_interrupt,
-       NULL, NULL, NULL, NULL, NULL,
-       bad_IRQ31_interrupt
-};
+static void enable_crisv10_irq(unsigned int irq);
+
+static unsigned int startup_crisv10_irq(unsigned int irq)
+{
+       enable_crisv10_irq(irq);
+       return 0;
+}
+
+#define shutdown_crisv10_irq   disable_crisv10_irq
 
-void arch_setup_irq(int irq)
+static void enable_crisv10_irq(unsigned int irq)
 {
-  set_int_vector(irq, interrupt[irq]);
+       unmask_irq(irq);
 }
 
-void arch_free_irq(int irq)
+static void disable_crisv10_irq(unsigned int irq)
 {
-  set_int_vector(irq, bad_interrupt[irq]);
+       mask_irq(irq);
 }
 
+static void ack_crisv10_irq(unsigned int irq)
+{
+}
+
+static void end_crisv10_irq(unsigned int irq)
+{
+}
+
+static struct hw_interrupt_type crisv10_irq_type = {
+       .typename =    "CRISv10",
+       .startup =     startup_crisv10_irq,
+       .shutdown =    shutdown_crisv10_irq,
+       .enable =      enable_crisv10_irq,
+       .disable =     disable_crisv10_irq,
+       .ack =         ack_crisv10_irq,
+       .end =         end_crisv10_irq,
+       .set_affinity = NULL
+};
+
 void weird_irq(void);
 void system_call(void);  /* from entry.S */
 void do_sigtrap(void); /* from entry.S */
 void gdb_handle_breakpoint(void); /* from entry.S */
 
 /* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and
-   setting the irq vector table to point to bad_interrupt ptrs.
+   setting the irq vector table.
 */
 
 void __init
@@ -154,14 +167,15 @@ init_IRQ(void)
 
        *R_VECT_MASK_CLR = 0xffffffff;
 
-       /* clear the shortcut entry points */
-
-       for(i = 0; i < NR_IRQS; i++)
-               irq_shortcuts[i] = NULL;
-        
         for (i = 0; i < 256; i++)
                etrax_irv->v[i] = weird_irq;
 
+       /* Initialize IRQ handler descriptiors. */
+       for(i = 2; i < NR_IRQS; i++) {
+               irq_desc[i].handler = &crisv10_irq_type;
+               set_int_vector(i, interrupt[i]);
+       }
+
         /* the entries in the break vector contain actual code to be
            executed by the associated break handler, rather than just a jump
            address. therefore we need to setup a default breakpoint handler
@@ -170,10 +184,6 @@ init_IRQ(void)
        for (i = 0; i < 16; i++)
                 set_break_vector(i, do_sigtrap);
         
-       /* set all etrax irq's to the bad handlers */
-       for (i = 2; i < NR_IRQS; i++)
-               set_int_vector(i, bad_interrupt[i]);
-        
        /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
 
        set_int_vector(15, multiple_interrupt);
index d848b94..30deaf1 100644 (file)
@@ -12,8 +12,6 @@
  * shouldn't result in any weird surprises, and installing new handlers
  * should be easier.
  *
- * Notice Linux/CRIS: these routines do not care about SMP
- *
  */
 
 /*
@@ -24,6 +22,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/ptrace.h>
+#include <linux/irq.h>
 
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
 #include <linux/init.h>
 #include <linux/seq_file.h>
 #include <linux/errno.h>
-#include <linux/bitops.h>
+#include <linux/spinlock.h>
 
 #include <asm/io.h>
 
-/* Defined in arch specific irq.c */
-extern void arch_setup_irq(int irq);
-extern void arch_free_irq(int irq);
-
-void
-disable_irq(unsigned int irq_nr)
-{
-       unsigned long flags;
-       
-       local_save_flags(flags);
-       local_irq_disable();
-       mask_irq(irq_nr);
-       local_irq_restore(flags);
-}
-
-void
-enable_irq(unsigned int irq_nr)
+void ack_bad_irq(unsigned int irq)
 {
-       unsigned long flags;
-       local_save_flags(flags);
-       local_irq_disable();
-       unmask_irq(irq_nr);
-       local_irq_restore(flags);
+       printk("unexpected IRQ trap at vector %02x\n", irq);
 }
 
-unsigned long
-probe_irq_on()
-{
-       return 0;
-}
-
-EXPORT_SYMBOL(probe_irq_on);
-
-int
-probe_irq_off(unsigned long x)
-{
-       return 0;
-}
-
-EXPORT_SYMBOL(probe_irq_off);
-
-/*
- * Initial irq handlers.
- */
-
-static struct irqaction *irq_action[NR_IRQS];
-
 int show_interrupts(struct seq_file *p, void *v)
 {
-       int i = *(loff_t *) v;
+       int i = *(loff_t *) v, j;
        struct irqaction * action;
        unsigned long flags;
 
+       if (i == 0) {
+               seq_printf(p, "           ");
+               for (j=0; j<NR_CPUS; j++)
+                       if (cpu_online(j))
+                               seq_printf(p, "CPU%d       ",j);
+               seq_putc(p, '\n');
+       }
+
        if (i < NR_IRQS) {
-               local_irq_save(flags);
-               action = irq_action[i];
-               if (!action) 
+               spin_lock_irqsave(&irq_desc[i].lock, flags);
+               action = irq_desc[i].action;
+               if (!action)
                        goto skip;
-               seq_printf(p, "%2d: %10u %c %s",
-                       i, kstat_this_cpu.irqs[i],
-                       (action->flags & SA_INTERRUPT) ? '+' : ' ',
-                       action->name);
-               for (action = action->next; action; action = action->next) {
-                       seq_printf(p, ",%s %s",
-                               (action->flags & SA_INTERRUPT) ? " +" : "",
-                               action->name);
-               }
+               seq_printf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+               seq_printf(p, "%10u ", kstat_irqs(i));
+#else
+               for (j = 0; j < NR_CPUS; j++)
+                       if (cpu_online(j))
+                               seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+#endif
+               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, "  %s", action->name);
+
+               for (action=action->next; action; action = action->next)
+                       seq_printf(p, ", %s", action->name);
+
                seq_putc(p, '\n');
 skip:
-               local_irq_restore(flags);
+               spin_unlock_irqrestore(&irq_desc[i].lock, flags);
        }
        return 0;
 }
 
+
 /* called by the assembler IRQ entry functions defined in irq.h
  * to dispatch the interrupts to registred handlers
  * interrupts are disabled upon entry - depending on if the
@@ -123,164 +94,17 @@ skip:
 
 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 {
-       struct irqaction *action;
-       int do_random, cpu;
-        int ret, retval = 0;
-
-        cpu = smp_processor_id();
-        irq_enter();
-       kstat_cpu(cpu).irqs[irq - FIRST_IRQ]++;
-       action = irq_action[irq - FIRST_IRQ];
-
-        if (action) {
-                if (!(action->flags & SA_INTERRUPT))
-                        local_irq_enable();
-                do_random = 0;
-                do {
-                       ret = action->handler(irq, action->dev_id, regs);
-                       if (ret == IRQ_HANDLED)
-                               do_random |= action->flags;
-                        retval |= ret;
-                        action = action->next;
-                } while (action);
-
-                if (retval != 1) {
-                       if (retval) {
-                               printk("irq event %d: bogus retval mask %x\n",
-                                       irq, retval);
-                       } else {
-                               printk("irq %d: nobody cared\n", irq);
-                       }
-               }
-
-                if (do_random & SA_SAMPLE_RANDOM)
-                        add_interrupt_randomness(irq);
-               local_irq_disable();
-        }
-        irq_exit();
-}
-
-/* this function links in a handler into the chain of handlers for the
-   given irq, and if the irq has never been registred, the appropriate
-   handler is entered into the interrupt vector
-*/
-
-int setup_irq(int irq, struct irqaction * new)
-{
-       int shared = 0;
-       struct irqaction *old, **p;
-       unsigned long flags;
-
-       p = irq_action + irq - FIRST_IRQ;
-       if ((old = *p) != NULL) {
-               /* Can't share interrupts unless both agree to */
-               if (!(old->flags & new->flags & SA_SHIRQ))
-                       return -EBUSY;
-
-               /* Can't share interrupts unless both are same type */
-               if ((old->flags ^ new->flags) & SA_INTERRUPT)
-                       return -EBUSY;
-
-               /* add new interrupt at end of irq queue */
-               do {
-                       p = &old->next;
-                       old = *p;
-               } while (old);
-               shared = 1;
-       }
-
-       if (new->flags & SA_SAMPLE_RANDOM)
-               rand_initialize_irq(irq);
-
-       local_save_flags(flags);
-       local_irq_disable();
-       *p = new;
-
-       if (!shared) {
-               /* if the irq wasn't registred before, enter it into the vector table
-                  and unmask it physically 
-               */
-               arch_setup_irq(irq);
-               unmask_irq(irq);
-       }
-       
-       local_irq_restore(flags);
-       return 0;
-}
-
-/* this function is called by a driver to register an irq handler
-   Valid flags:
-   SA_INTERRUPT -> it's a fast interrupt, handler called with irq disabled and
-                   no signal checking etc is performed upon exit
-   SA_SHIRQ -> the interrupt can be shared between different handlers, the handler
-                is required to check if the irq was "aimed" at it explicitely
-   SA_RANDOM -> the interrupt will add to the random generators entropy
-*/
-
-int request_irq(unsigned int irq, 
-               irqreturn_t (*handler)(int, void *, struct pt_regs *),
-               unsigned long irqflags, 
-               const char * devname,
-               void *dev_id)
-{
-       int retval;
-       struct irqaction * action;
-
-       if(!handler)
-               return -EINVAL;
-
-       /* allocate and fill in a handler structure and setup the irq */
-
-       action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
-       if (!action)
-               return -ENOMEM;
-
-       action->handler = handler;
-       action->flags = irqflags;
-       cpus_clear(action->mask);
-       action->name = devname;
-       action->next = NULL;
-       action->dev_id = dev_id;
-
-       retval = setup_irq(irq, action);
-
-       if (retval)
-               kfree(action);
-       return retval;
-}
-
-EXPORT_SYMBOL(request_irq);
-               
-void free_irq(unsigned int irq, void *dev_id)
-{
-       struct irqaction * action, **p;
-       unsigned long flags;
-
-       if (irq >= NR_IRQS) {
-               printk("Trying to free IRQ%d\n",irq);
-               return;
+       unsigned long sp;
+       irq_enter();
+       sp = rdsp();
+       if (unlikely((sp & (PAGE_SIZE - 1)) < (PAGE_SIZE/8))) {
+               printk("do_IRQ: stack overflow: %lX\n", sp);
+               show_stack(NULL, (unsigned long *)sp);
        }
-       for (p = irq - FIRST_IRQ + irq_action; (action = *p) != NULL; p = &action->next) {
-               if (action->dev_id != dev_id)
-                       continue;
-
-               /* Found it - now free it */
-               local_save_flags(flags);
-               local_irq_disable();
-               *p = action->next;
-               if (!irq_action[irq - FIRST_IRQ]) {
-                       mask_irq(irq);
-                       arch_free_irq(irq);
-               }
-               local_irq_restore(flags);
-               kfree(action);
-               return;
-       }
-       printk("Trying to free free IRQ%d\n",irq);
+       __do_IRQ(irq, regs);
+        irq_exit();
 }
 
-EXPORT_SYMBOL(free_irq);
-
 void weird_irq(void)
 {
        local_irq_disable();
@@ -288,10 +112,3 @@ void weird_irq(void)
        while(1);
 }
 
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
-/* Used by other archs to show/control IRQ steering during SMP */
-void __init
-init_irq_proc(void)
-{
-}
-#endif
index a2a6e15..4fa8945 100644 (file)
@@ -74,12 +74,9 @@ struct etrax_interrupt_vector {
 };
 
 extern struct etrax_interrupt_vector *etrax_irv;
-void set_int_vector(int n, irqvectptr addr, irqvectptr saddr);
+void set_int_vector(int n, irqvectptr addr);
 void set_break_vector(int n, irqvectptr addr);
 
-#define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
-#define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
-
 #define __STR(x) #x
 #define STR(x) __STR(x)
  
@@ -121,26 +118,17 @@ void set_break_vector(int n, irqvectptr addr);
 
 #define BUILD_IRQ(nr,mask) \
 void IRQ_NAME(nr); \
-void sIRQ_NAME(nr); \
-void BAD_IRQ_NAME(nr); \
 __asm__ ( \
           ".text\n\t" \
           "IRQ" #nr "_interrupt:\n\t" \
          SAVE_ALL \
-         "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \
          BLOCK_IRQ(mask,nr) /* this must be done to prevent irq loops when we ei later */ \
          "moveq "#nr",$r10\n\t" \
          "move.d $sp,$r11\n\t" \
          "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \
          UNBLOCK_IRQ(mask) \
          "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \
-         "jump ret_from_intr\n\t" \
-          "bad_IRQ" #nr "_interrupt:\n\t" \
-         "push $r0\n\t" \
-         BLOCK_IRQ(mask,nr) \
-         "pop $r0\n\t" \
-          "reti\n\t" \
-          "nop\n");
+         "jump ret_from_intr\n\t");
 
 /* This is subtle. The timer interrupt is crucial and it should not be disabled for 
  * too long. However, if it had been a normal interrupt as per BUILD_IRQ, it would
@@ -159,23 +147,14 @@ __asm__ ( \
 
 #define BUILD_TIMER_IRQ(nr,mask) \
 void IRQ_NAME(nr); \
-void sIRQ_NAME(nr); \
-void BAD_IRQ_NAME(nr); \
 __asm__ ( \
           ".text\n\t" \
           "IRQ" #nr "_interrupt:\n\t" \
          SAVE_ALL \
-         "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \
          "moveq "#nr",$r10\n\t" \
          "move.d $sp,$r11\n\t" \
          "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \
          "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \
-         "jump ret_from_intr\n\t" \
-          "bad_IRQ" #nr "_interrupt:\n\t" \
-         "push $r0\n\t" \
-         BLOCK_IRQ(mask,nr) \
-         "pop $r0\n\t" \
-          "reti\n\t" \
-          "nop\n");
+         "jump ret_from_intr\n\t");
 
 #endif
index f4d1362..1c13dd3 100644 (file)
@@ -1,18 +1,17 @@
 #ifndef __ASM_HARDIRQ_H
 #define __ASM_HARDIRQ_H
 
-/* only non-SMP supported */
-
 #include <linux/threads.h>
 #include <linux/cache.h>
 
-/* entry.S is sensitive to the offsets of these fields */
 typedef struct {
        unsigned int __softirq_pending;
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
 
+void ack_bad_irq(unsigned int irq);
+
 #define HARDIRQ_BITS   8
 
 /*
diff --git a/include/asm-cris/hw_irq.h b/include/asm-cris/hw_irq.h
new file mode 100644 (file)
index 0000000..341536a
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _ASM_HW_IRQ_H
+#define _ASM_HW_IRQ_H
+
+static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
+
+#endif
+
index 87f3425..8e787fd 100644 (file)
@@ -8,16 +8,6 @@ extern __inline__ int irq_canonicalize(int irq)
   return irq; 
 }
 
-extern void disable_irq(unsigned int);
-extern void enable_irq(unsigned int);
-
-#define disable_irq_nosync      disable_irq
-#define enable_irq_nosync       enable_irq
-
-struct irqaction;
-struct pt_regs;
-int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
-
 #endif  /* _ASM_IRQ_H */