diff options
Diffstat (limited to 'arch/mips/kernel/irq_cpu.c')
| -rw-r--r-- | arch/mips/kernel/irq_cpu.c | 188 |
1 files changed, 82 insertions, 106 deletions
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index 5db67e31ec1..e498f2b3646 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -3,13 +3,13 @@ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net * * Copyright (C) 2001 Ralf Baechle - * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. - * Author: Maciej W. Rozycki <macro@mips.com> + * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. + * Author: Maciej W. Rozycki <macro@mips.com> * * This file define the irq handler for MIPS CPU interrupts. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ @@ -25,157 +25,133 @@ * Don't even think about using this on SMP. You have been warned. * * This file exports one global function: - * void mips_cpu_irq_init(int irq_base); + * void mips_cpu_irq_init(void); */ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> #include <asm/irq_cpu.h> #include <asm/mipsregs.h> #include <asm/mipsmtregs.h> -#include <asm/system.h> -static int mips_cpu_irq_base; - -static inline void unmask_mips_irq(unsigned int irq) +static inline void unmask_mips_irq(struct irq_data *d) { - set_c0_status(0x100 << (irq - mips_cpu_irq_base)); + set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); irq_enable_hazard(); } -static inline void mask_mips_irq(unsigned int irq) +static inline void mask_mips_irq(struct irq_data *d) { - clear_c0_status(0x100 << (irq - mips_cpu_irq_base)); + clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); irq_disable_hazard(); } -static inline void mips_cpu_irq_enable(unsigned int irq) -{ - unsigned long flags; - - local_irq_save(flags); - unmask_mips_irq(irq); - back_to_back_c0_hazard(); - local_irq_restore(flags); -} - -static void mips_cpu_irq_disable(unsigned int irq) -{ - unsigned long flags; +static struct irq_chip mips_cpu_irq_controller = { + .name = "MIPS", + .irq_ack = mask_mips_irq, + .irq_mask = mask_mips_irq, + .irq_mask_ack = mask_mips_irq, + .irq_unmask = unmask_mips_irq, + .irq_eoi = unmask_mips_irq, +}; - local_irq_save(flags); - mask_mips_irq(irq); - back_to_back_c0_hazard(); - local_irq_restore(flags); -} +/* + * Basically the same as above but taking care of all the MT stuff + */ -static unsigned int mips_cpu_irq_startup(unsigned int irq) +static unsigned int mips_mt_cpu_irq_startup(struct irq_data *d) { - mips_cpu_irq_enable(irq); + unsigned int vpflags = dvpe(); + clear_c0_cause(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); + evpe(vpflags); + unmask_mips_irq(d); return 0; } -#define mips_cpu_irq_shutdown mips_cpu_irq_disable - /* * While we ack the interrupt interrupts are disabled and thus we don't need * to deal with concurrency issues. Same for mips_cpu_irq_end. */ -static void mips_cpu_irq_ack(unsigned int irq) +static void mips_mt_cpu_irq_ack(struct irq_data *d) { - mask_mips_irq(irq); + unsigned int vpflags = dvpe(); + clear_c0_cause(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); + evpe(vpflags); + mask_mips_irq(d); } -static void mips_cpu_irq_end(unsigned int irq) +static struct irq_chip mips_mt_cpu_irq_controller = { + .name = "MIPS", + .irq_startup = mips_mt_cpu_irq_startup, + .irq_ack = mips_mt_cpu_irq_ack, + .irq_mask = mask_mips_irq, + .irq_mask_ack = mips_mt_cpu_irq_ack, + .irq_unmask = unmask_mips_irq, + .irq_eoi = unmask_mips_irq, +}; + +void __init mips_cpu_irq_init(void) { - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - unmask_mips_irq(irq); -} + int irq_base = MIPS_CPU_IRQ_BASE; + int i; -static hw_irq_controller mips_cpu_irq_controller = { - .typename = "MIPS", - .startup = mips_cpu_irq_startup, - .shutdown = mips_cpu_irq_shutdown, - .enable = mips_cpu_irq_enable, - .disable = mips_cpu_irq_disable, - .ack = mips_cpu_irq_ack, - .end = mips_cpu_irq_end, -}; + /* Mask interrupts. */ + clear_c0_status(ST0_IM); + clear_c0_cause(CAUSEF_IP); -/* - * Basically the same as above but taking care of all the MT stuff - */ + /* Software interrupts are used for MT/CMT IPI */ + for (i = irq_base; i < irq_base + 2; i++) + irq_set_chip_and_handler(i, cpu_has_mipsmt ? + &mips_mt_cpu_irq_controller : + &mips_cpu_irq_controller, + handle_percpu_irq); -#define unmask_mips_mt_irq unmask_mips_irq -#define mask_mips_mt_irq mask_mips_irq -#define mips_mt_cpu_irq_enable mips_cpu_irq_enable -#define mips_mt_cpu_irq_disable mips_cpu_irq_disable + for (i = irq_base + 2; i < irq_base + 8; i++) + irq_set_chip_and_handler(i, &mips_cpu_irq_controller, + handle_percpu_irq); +} -static unsigned int mips_mt_cpu_irq_startup(unsigned int irq) +#ifdef CONFIG_IRQ_DOMAIN +static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) { - unsigned int vpflags = dvpe(); + static struct irq_chip *chip; - clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); - evpe(vpflags); - mips_mt_cpu_irq_enable(irq); - - return 0; -} + if (hw < 2 && cpu_has_mipsmt) { + /* Software interrupts are used for MT/CMT IPI */ + chip = &mips_mt_cpu_irq_controller; + } else { + chip = &mips_cpu_irq_controller; + } -#define mips_mt_cpu_irq_shutdown mips_mt_cpu_irq_disable + irq_set_chip_and_handler(irq, chip, handle_percpu_irq); -/* - * While we ack the interrupt interrupts are disabled and thus we don't need - * to deal with concurrency issues. Same for mips_cpu_irq_end. - */ -static void mips_mt_cpu_irq_ack(unsigned int irq) -{ - unsigned int vpflags = dvpe(); - clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); - evpe(vpflags); - mask_mips_mt_irq(irq); + return 0; } -#define mips_mt_cpu_irq_end mips_cpu_irq_end - -static hw_irq_controller mips_mt_cpu_irq_controller = { - .typename = "MIPS", - .startup = mips_mt_cpu_irq_startup, - .shutdown = mips_mt_cpu_irq_shutdown, - .enable = mips_mt_cpu_irq_enable, - .disable = mips_mt_cpu_irq_disable, - .ack = mips_mt_cpu_irq_ack, - .end = mips_mt_cpu_irq_end, +static const struct irq_domain_ops mips_cpu_intc_irq_domain_ops = { + .map = mips_cpu_intc_map, + .xlate = irq_domain_xlate_onecell, }; -void __init mips_cpu_irq_init(int irq_base) +int __init mips_cpu_intc_init(struct device_node *of_node, + struct device_node *parent) { - int i; + struct irq_domain *domain; /* Mask interrupts. */ clear_c0_status(ST0_IM); clear_c0_cause(CAUSEF_IP); - /* - * Only MT is using the software interrupts currently, so we just - * leave them uninitialized for other processors. - */ - if (cpu_has_mipsmt) - for (i = irq_base; i < irq_base + 2; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = NULL; - irq_desc[i].depth = 1; - irq_desc[i].handler = &mips_mt_cpu_irq_controller; - } - - for (i = irq_base + 2; i < irq_base + 8; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = NULL; - irq_desc[i].depth = 1; - irq_desc[i].handler = &mips_cpu_irq_controller; - } + domain = irq_domain_add_legacy(of_node, 8, MIPS_CPU_IRQ_BASE, 0, + &mips_cpu_intc_irq_domain_ops, NULL); + if (!domain) + panic("Failed to add irqdomain for MIPS CPU"); - mips_cpu_irq_base = irq_base; + return 0; } +#endif /* CONFIG_IRQ_DOMAIN */ |
