Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / cris / kernel / irq.c
index d848b94..b504def 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_each_online_cpu(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_each_online_cpu(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 +92,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 +110,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