From 2e0cea1decf7f21df0496571c218df3b3b8cce99 Mon Sep 17 00:00:00 2001 From: Mikael Starvik Date: Wed, 27 Jul 2005 11:44:36 -0700 Subject: [PATCH] [PATCH] CRIS update: IRQ Use the generic IRQ framework Signed-off-by: Mikael Starvik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/cris/arch-v10/kernel/irq.c | 86 ++++++----- arch/cris/kernel/irq.c | 263 +++++--------------------------- include/asm-cris/arch-v10/irq.h | 27 +--- include/asm-cris/hardirq.h | 5 +- include/asm-cris/hw_irq.h | 7 + include/asm-cris/irq.h | 10 -- 6 files changed, 100 insertions(+), 298 deletions(-) create mode 100644 include/asm-cris/hw_irq.h 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 +#include #include #include #include -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 + +static void enable_crisv10_irq(unsigned int irq) +{ + unmask_irq(irq); +} + +static void disable_crisv10_irq(unsigned int 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 arch_setup_irq(int irq) -{ - set_int_vector(irq, interrupt[irq]); -} - -void arch_free_irq(int irq) -{ - set_int_vector(irq, bad_interrupt[irq]); -} - 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 #include #include +#include #include #include @@ -36,84 +35,56 @@ #include #include #include -#include +#include #include -/* 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) +void ack_bad_irq(unsigned int irq) { - unsigned long flags; - - local_save_flags(flags); - local_irq_disable(); - mask_irq(irq_nr); - local_irq_restore(flags); + printk("unexpected IRQ trap at vector %02x\n", irq); } -void -enable_irq(unsigned int irq_nr) -{ - unsigned long flags; - local_save_flags(flags); - local_irq_disable(); - unmask_irq(irq_nr); - local_irq_restore(flags); -} - -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; jflags & 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(); - } + 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); + } + __do_IRQ(irq, regs); 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; - } - 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); -} - -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 diff --git a/include/asm-cris/arch-v10/irq.h b/include/asm-cris/arch-v10/irq.h index a2a6e1533ea0..4fa8945b0263 100644 --- a/include/asm-cris/arch-v10/irq.h +++ b/include/asm-cris/arch-v10/irq.h @@ -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 diff --git a/include/asm-cris/hardirq.h b/include/asm-cris/hardirq.h index f4d136228ee1..1c13dd3faac3 100644 --- a/include/asm-cris/hardirq.h +++ b/include/asm-cris/hardirq.h @@ -1,18 +1,17 @@ #ifndef __ASM_HARDIRQ_H #define __ASM_HARDIRQ_H -/* only non-SMP supported */ - #include #include -/* entry.S is sensitive to the offsets of these fields */ typedef struct { unsigned int __softirq_pending; } ____cacheline_aligned irq_cpustat_t; #include /* 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 index 000000000000..341536a234e9 --- /dev/null +++ b/include/asm-cris/hw_irq.h @@ -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 + diff --git a/include/asm-cris/irq.h b/include/asm-cris/irq.h index 87f342517bb1..8e787fdaedd4 100644 --- a/include/asm-cris/irq.h +++ b/include/asm-cris/irq.h @@ -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 */