summary refs log tree commit diff
path: root/arch/cris
diff options
context:
space:
mode:
authorMikael Starvik <mikael.starvik@axis.com>2005-07-27 11:44:36 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-27 16:26:00 -0700
commit2e0cea1decf7f21df0496571c218df3b3b8cce99 (patch)
tree7d6a2a99013b2a4270f4d0a9ccf2d71549488f48 /arch/cris
parent63245d2cde2be64f172388c2c50862f233c05700 (diff)
downloadlinux-2e0cea1decf7f21df0496571c218df3b3b8cce99.tar.gz
[PATCH] CRIS update: IRQ
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>
Diffstat (limited to 'arch/cris')
-rw-r--r--arch/cris/arch-v10/kernel/irq.c76
-rw-r--r--arch/cris/kernel/irq.c263
2 files changed, 83 insertions, 256 deletions
diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c
index b2f16d6fc871..4b368a122015 100644
--- a/arch/cris/arch-v10/kernel/irq.c
+++ b/arch/cris/arch-v10/kernel/irq.c
@@ -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
  *
@@ -12,11 +12,13 @@
  */
 
 #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);
diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c
index d848b9407457..30deaf1b728a 100644
--- a/arch/cris/kernel/irq.c
+++ b/arch/cris/kernel/irq.c
@@ -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>
@@ -36,84 +35,56 @@
 #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