diff options
Diffstat (limited to 'arch/m68k/kernel/ints.c')
| -rw-r--r-- | arch/m68k/kernel/ints.c | 294 |
1 files changed, 91 insertions, 203 deletions
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c index 514d323ad53..5b8d66fbf38 100644 --- a/arch/m68k/kernel/ints.c +++ b/arch/m68k/kernel/ints.c @@ -4,81 +4,44 @@ * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. - * - * 07/03/96: Timer initialization, and thus mach_sched_init(), - * removed from request_irq() and moved to init_time(). - * We should therefore consider renaming our add_isr() and - * remove_isr() to request_irq() and free_irq() - * respectively, so they are compliant with the other - * architectures. /Jes - * 11/07/96: Changed all add_/remove_isr() to request_/free_irq() calls. - * Removed irq list support, if any machine needs an irq server - * it must implement this itself (as it's already done), instead - * only default handler are used with mach_default_handler. - * request_irq got some flags different from other architectures: - * - IRQ_FLG_REPLACE : Replace an existing handler (the default one - * can be replaced without this flag) - * - IRQ_FLG_LOCK : handler can't be replaced - * There are other machine depending flags, see there - * If you want to replace a default handler you should know what - * you're doing, since it might handle different other irq sources - * which must be served /Roman Zippel */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> #include <linux/sched.h> -#include <linux/kernel_stat.h> +#include <linux/interrupt.h> #include <linux/errno.h> #include <linux/init.h> +#include <linux/irq.h> #include <asm/setup.h> -#include <asm/system.h> #include <asm/irq.h> #include <asm/traps.h> #include <asm/page.h> #include <asm/machdep.h> +#include <asm/cacheflush.h> +#include <asm/irq_regs.h> #ifdef CONFIG_Q40 #include <asm/q40ints.h> #endif -/* table for system interrupt handlers */ -static irq_handler_t irq_list[SYS_IRQS]; - -static const char *default_names[SYS_IRQS] = { - [0] = "spurious int", - [1] = "int1 handler", - [2] = "int2 handler", - [3] = "int3 handler", - [4] = "int4 handler", - [5] = "int5 handler", - [6] = "int6 handler", - [7] = "int7 handler" -}; - -/* The number of spurious interrupts */ -volatile unsigned int num_spurious; +extern u32 auto_irqhandler_fixup[]; +extern u16 user_irqvec_fixup[]; -#define NUM_IRQ_NODES 100 -static irq_node_t nodes[NUM_IRQ_NODES]; +static int m68k_first_user_vec; -static void dummy_enable_irq(unsigned int irq); -static void dummy_disable_irq(unsigned int irq); -static int dummy_request_irq(unsigned int irq, - irqreturn_t (*handler) (int, void *, struct pt_regs *), - unsigned long flags, const char *devname, void *dev_id); -static void dummy_free_irq(unsigned int irq, void *dev_id); - -void (*enable_irq) (unsigned int) = dummy_enable_irq; -void (*disable_irq) (unsigned int) = dummy_disable_irq; - -int (*mach_request_irq) (unsigned int, irqreturn_t (*)(int, void *, struct pt_regs *), - unsigned long, const char *, void *) = dummy_request_irq; -void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq; +static struct irq_chip auto_irq_chip = { + .name = "auto", + .irq_startup = m68k_irq_startup, + .irq_shutdown = m68k_irq_shutdown, +}; -void init_irq_proc(void); +static struct irq_chip user_irq_chip = { + .name = "user", + .irq_startup = m68k_irq_startup, + .irq_shutdown = m68k_irq_shutdown, +}; /* * void init_IRQ(void) @@ -95,187 +58,112 @@ void __init init_IRQ(void) { int i; - for (i = 0; i < SYS_IRQS; i++) { - if (mach_default_handler) - irq_list[i].handler = (*mach_default_handler)[i]; - irq_list[i].flags = 0; - irq_list[i].dev_id = NULL; - irq_list[i].devname = default_names[i]; - } - - for (i = 0; i < NUM_IRQ_NODES; i++) - nodes[i].handler = NULL; - - mach_init_IRQ (); -} - -irq_node_t *new_irq_node(void) -{ - irq_node_t *node; - short i; - - for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) - if (!node->handler) - return node; + for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) + irq_set_chip_and_handler(i, &auto_irq_chip, handle_simple_irq); - printk ("new_irq_node: out of nodes\n"); - return NULL; + mach_init_IRQ(); } -/* - * We will keep these functions until I have convinced Linus to move - * the declaration of them from include/linux/sched.h to - * include/asm/irq.h. +/** + * m68k_setup_auto_interrupt + * @handler: called from auto vector interrupts + * + * setup the handler to be called from auto vector interrupts instead of the + * standard do_IRQ(), it will be called with irq numbers in the range + * from IRQ_AUTO_1 - IRQ_AUTO_7. */ -int request_irq(unsigned int irq, - irqreturn_t (*handler) (int, void *, struct pt_regs *), - unsigned long flags, const char *devname, void *dev_id) -{ - return mach_request_irq(irq, handler, flags, devname, dev_id); -} - -EXPORT_SYMBOL(request_irq); - -void free_irq(unsigned int irq, void *dev_id) +void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *)) { - mach_free_irq(irq, dev_id); + if (handler) + *auto_irqhandler_fixup = (u32)handler; + flush_icache(); } -EXPORT_SYMBOL(free_irq); - -int cpu_request_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, void *dev_id) -{ - if (irq < IRQ1 || irq > IRQ7) { - printk("%s: Incorrect IRQ %d from %s\n", - __FUNCTION__, irq, devname); - return -ENXIO; - } - -#if 0 - if (!(irq_list[irq].flags & IRQ_FLG_STD)) { - if (irq_list[irq].flags & IRQ_FLG_LOCK) { - printk("%s: IRQ %d from %s is not replaceable\n", - __FUNCTION__, irq, irq_list[irq].devname); - return -EBUSY; - } - if (!(flags & IRQ_FLG_REPLACE)) { - printk("%s: %s can't replace IRQ %d from %s\n", - __FUNCTION__, devname, irq, irq_list[irq].devname); - return -EBUSY; - } - } -#endif - - irq_list[irq].handler = handler; - irq_list[irq].flags = flags; - irq_list[irq].dev_id = dev_id; - irq_list[irq].devname = devname; - return 0; -} - -void cpu_free_irq(unsigned int irq, void *dev_id) +/** + * m68k_setup_user_interrupt + * @vec: first user vector interrupt to handle + * @cnt: number of active user vector interrupts + * + * setup user vector interrupts, this includes activating the specified range + * of interrupts, only then these interrupts can be requested (note: this is + * different from auto vector interrupts). + */ +void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt) { - if (irq < IRQ1 || irq > IRQ7) { - printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); - return; - } - - if (irq_list[irq].dev_id != dev_id) - printk("%s: Removing probably wrong IRQ %d from %s\n", - __FUNCTION__, irq, irq_list[irq].devname); + int i; - irq_list[irq].handler = (*mach_default_handler)[irq]; - irq_list[irq].flags = 0; - irq_list[irq].dev_id = NULL; - irq_list[irq].devname = default_names[irq]; + BUG_ON(IRQ_USER + cnt > NR_IRQS); + m68k_first_user_vec = vec; + for (i = 0; i < cnt; i++) + irq_set_chip_and_handler(i, &user_irq_chip, handle_simple_irq); + *user_irqvec_fixup = vec - IRQ_USER; + flush_icache(); } -/* - * Do we need these probe functions on the m68k? +/** + * m68k_setup_irq_controller + * @chip: irq chip which controls specified irq + * @handle: flow handler which handles specified irq + * @irq: first irq to be managed by the controller + * @cnt: number of irqs to be managed by the controller * - * ... may be useful with ISA devices + * Change the controller for the specified range of irq, which will be used to + * manage these irq. auto/user irq already have a default controller, which can + * be changed as well, but the controller probably should use m68k_irq_startup/ + * m68k_irq_shutdown. */ -unsigned long probe_irq_on (void) +void m68k_setup_irq_controller(struct irq_chip *chip, + irq_flow_handler_t handle, unsigned int irq, + unsigned int cnt) { -#ifdef CONFIG_Q40 - if (MACH_IS_Q40) - return q40_probe_irq_on(); -#endif - return 0; -} + int i; -EXPORT_SYMBOL(probe_irq_on); + for (i = 0; i < cnt; i++) { + irq_set_chip(irq + i, chip); + if (handle) + irq_set_handler(irq + i, handle); + } +} -int probe_irq_off (unsigned long irqs) +unsigned int m68k_irq_startup_irq(unsigned int irq) { -#ifdef CONFIG_Q40 - if (MACH_IS_Q40) - return q40_probe_irq_off(irqs); -#endif + if (irq <= IRQ_AUTO_7) + vectors[VEC_SPUR + irq] = auto_inthandler; + else + vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler; return 0; } -EXPORT_SYMBOL(probe_irq_off); - -static void dummy_enable_irq(unsigned int irq) +unsigned int m68k_irq_startup(struct irq_data *data) { - printk("calling uninitialized enable_irq()\n"); + return m68k_irq_startup_irq(data->irq); } -static void dummy_disable_irq(unsigned int irq) +void m68k_irq_shutdown(struct irq_data *data) { - printk("calling uninitialized disable_irq()\n"); -} + unsigned int irq = data->irq; -static int dummy_request_irq(unsigned int irq, - irqreturn_t (*handler) (int, void *, struct pt_regs *), - unsigned long flags, const char *devname, void *dev_id) -{ - printk("calling uninitialized request_irq()\n"); - return 0; + if (irq <= IRQ_AUTO_7) + vectors[VEC_SPUR + irq] = bad_inthandler; + else + vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler; } -static void dummy_free_irq(unsigned int irq, void *dev_id) -{ - printk("calling uninitialized disable_irq()\n"); -} -asmlinkage void process_int(unsigned long vec, struct pt_regs *fp) +unsigned int irq_canonicalize(unsigned int irq) { - if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) { - vec -= VEC_SPUR; - kstat_cpu(0).irqs[vec]++; - irq_list[vec].handler(vec, irq_list[vec].dev_id, fp); - } else { - if (mach_process_int) - mach_process_int(vec, fp); - else - panic("Can't process interrupt vector %ld\n", vec); - return; - } +#ifdef CONFIG_Q40 + if (MACH_IS_Q40 && irq == 11) + irq = 10; +#endif + return irq; } -int show_interrupts(struct seq_file *p, void *v) -{ - int i = *(loff_t *) v; +EXPORT_SYMBOL(irq_canonicalize); - /* autovector interrupts */ - if (i < SYS_IRQS) { - if (mach_default_handler) { - seq_printf(p, "auto %2d: %10u ", i, - i ? kstat_cpu(0).irqs[i] : num_spurious); - seq_puts(p, " "); - seq_printf(p, "%s\n", irq_list[i].devname); - } - } else if (i == SYS_IRQS) - mach_get_irq_list(p, v); - return 0; -} -void init_irq_proc(void) +asmlinkage void handle_badint(struct pt_regs *regs) { - /* Insert /proc/irq driver here */ + atomic_inc(&irq_err_count); + pr_warn("unexpected interrupt from %u\n", regs->vector); } - |
